From 106a9720d13af2127c0b684dd5de8d6787982594 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Thu, 24 Nov 2016 04:35:48 +0000 Subject: [PATCH 01/17] Bundled output for commit 81216e232e99c3e85c9ba645d2dfd66922a7472c [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e1be8c2b..f748cef7 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,6 @@ There are over 4000 assertions in the test suite, and tests cover even difficult ## Modularity -Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at 7.42 KB min+gzip +Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at 7.40 KB min+gzip In addition, Mithril is now completely modular: you can import only the modules that you need and easily integrate 3rd party modules if you wish to use a different library for routing, ajax, and even rendering From edf3c5eaf772584013cb728855ff124584db2094 Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Thu, 24 Nov 2016 12:25:00 +0000 Subject: [PATCH 02/17] Tests for contenteditable trust, including failing test for #1421 --- render/tests/test-attributes.js | 58 +++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index 6df82eaf..73cbd685 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -79,9 +79,9 @@ o.spec("attributes", function() { o.spec("canvas width and height", function() { o("uses attribute API", function() { var canvas = {tag: "canvas", attrs: {width: "100%"}} - + render(root, canvas) - + o(canvas.dom.attributes["width"].nodeValue).equals("100%") o(canvas.dom.width).equals(100) }) @@ -95,4 +95,58 @@ o.spec("attributes", function() { o(a.dom.attributes["class"].nodeValue).equals("test") }) }) + o.spec("contenteditable throws on untrusted children", function() { + o("including text nodes", function() { + var div = {tag: "div", attrs: {contenteditable: true}, text: ''} + var succeeded = false + + try { + render(root, div) + + succeeded = true + } + catch(e){} + + o(succeeded).equals(false) + }) + o("including elements", function() { + var div = {tag: "div", attrs: {contenteditable: true}, children: [{tag: "script", attrs: {src: "http://evil.com"}}]} + var succeeded = false + + try { + render(root, div) + + succeeded = true + } + catch(e){} + + o(succeeded).equals(false) + }) + o("tolerating empty children", function() { + var div = {tag: "div", attrs: {contenteditable: true}, children: []} + var succeeded = false + + try { + render(root, div) + + succeeded = true + } + catch(e){} + + o(succeeded).equals(true) + }) + o("tolerating trusted content", function() { + var div = {tag: "div", attrs: {contenteditable: true}, children: [{tag: "<", children: ""}]} + var succeeded = false + + try { + render(root, div) + + succeeded = true + } + catch(e){} + + o(succeeded).equals(true) + }) + }) }) From e8669ad5c80310299d458a5c12bc82191c8ffa0e Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Thu, 24 Nov 2016 12:29:45 +0000 Subject: [PATCH 03/17] Fix #1421 --- render/render.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/render/render.js b/render/render.js index 909477a2..c31a79ce 100644 --- a/render/render.js +++ b/render/render.js @@ -135,7 +135,7 @@ module.exports = function($window) { else { var recycling = isRecyclable(old, vnodes) if (recycling) old = old.concat(old.pool) - + var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map while (oldEnd >= oldStart && end >= start) { var o = old[oldStart], v = vnodes[start] @@ -347,7 +347,7 @@ module.exports = function($window) { var content = children[0].children if (vnode.dom.innerHTML !== content) vnode.dom.innerHTML = content } - else if (children != null || vnode.text != null) throw new Error("Child node of a contenteditable must be trusted") + else if (vnode.text != null || children != null && children.length !== 0) throw new Error("Child node of a contenteditable must be trusted") } //remove From b87cf7b28853aab4cd306afc24d7507b81027c32 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Thu, 24 Nov 2016 13:19:40 +0000 Subject: [PATCH 04/17] Bundled output for commit b4ada9284c47b14de50f2190380507046cbb18e1 [skip ci] --- README.md | 2 +- mithril.js | 3 +- mithril.min.js | 78 +++++++++++++++++++++++++------------------------- 3 files changed, 41 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index f748cef7..71c22280 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,6 @@ There are over 4000 assertions in the test suite, and tests cover even difficult ## Modularity -Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at 7.40 KB min+gzip +Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at 7.41 KB min+gzip In addition, Mithril is now completely modular: you can import only the modules that you need and easily integrate 3rd party modules if you wish to use a different library for routing, ajax, and even rendering diff --git a/mithril.js b/mithril.js index 7fdbec3a..a81fa58e 100644 --- a/mithril.js +++ b/mithril.js @@ -467,7 +467,6 @@ var _13 = function($window) { else { var recycling = isRecyclable(old, vnodes) if (recycling) old = old.concat(old.pool) - var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map while (oldEnd >= oldStart && end >= start) { var o = old[oldStart], v = vnodes[start] @@ -677,7 +676,7 @@ var _13 = function($window) { var content = children[0].children if (vnode.dom.innerHTML !== content) vnode.dom.innerHTML = content } - else if (children != null || vnode.text != null) throw new Error("Child node of a contenteditable must be trusted") + else if (vnode.text != null || children != null && children.length !== 0) throw new Error("Child node of a contenteditable must be trusted") } //remove function removeNodes(vnodes, start, end, context) { diff --git a/mithril.min.js b/mithril.min.js index 41590c4a..044beb36 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,40 +1,40 @@ -new function(){function m(a,b,k,e,l,h){return{tag:a,key:b,attrs:k,children:e,text:l,dom:h,domSize:void 0,state:{},events:void 0,instance:void 0,skip:!1}}function t(a){if(null==a||"string"!==typeof a&&null==a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a&&void 0===H[a]){for(var b,k,e=[],l={};b=O.exec(a);){var h=b[1],v=b[2];""===h&&""!==v?k=v:"#"===h?l.id=v:"."===h?e.push(v):"["===b[3][0]&&((h=b[6])&&(h=h.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")), -"class"===b[4]?e.push(h):l[b[4]]=h||!0)}0a.indexOf("?")?"?":"&";a+=e+f}return a}function v(a){try{return""!== -a?JSON.parse(a):null}catch(w){throw Error(a);}}function p(a){return a.responseText}function r(a,b){if("function"===typeof a)if(b instanceof Array)for(var e=0;en.status||304===n.status)b(r(f.type,a));else{var h=Error(n.responseText),k;for(k in a)h[k]=a[k];e(h)}}catch(G){e(G)}}; -u&&null!=f.data?n.send(f.data):n.send()}))},jsonp:function(f){return e(new b(function(b,e){var n=f.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=a.document.createElement("script");a[n]=function(e){k.parentNode.removeChild(k);b(r(f.type,e));delete a[n]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete a[n]};null==f.data&&(f.data={});f.url=l(f.url,f.data);f.data[f.callbackKey||"callback"]=n;k.src=h(f.url,f.data);a.document.documentElement.appendChild(k)}))}, -setCompletionCallback:function(a){q=a}}}(window,"undefined"!==typeof Promise?Promise:y),J=function(){var a=[];return{subscribe:a.push.bind(a),unsubscribe:function(b){b=a.indexOf(b);-1=A&&B>=l;){var x=a[A],m=d[l];if(x!==m||g)if(null==x)A++;else if(null==m)l++;else if(x.key===m.key)A++,l++,h(c,x,m,f,p(a,A,e),g,n),g&&x.tag===m.tag&&r(c,v(x),e); -else if(x=a[q],x!==m||g)if(null==x)q--;else if(null==m)l++;else if(x.key===m.key)h(c,x,m,f,p(a,q+1,e),g,n),(g||l=A&&B>=l;){x=a[q];m=d[B];if(x!==m||g)if(null==x)q--;else{if(null!=m)if(x.key===m.key)h(c,x,m,f,p(a,q+1,e),g,n),g&&x.tag===m.tag&&r(c,v(x),e),null!=x.dom&&(e=x.dom),q--;else{if(!w){w=a;var x=q,D={},z;for(z=0;za.indexOf("?")?"?":"&";a+=d+g}return a}function v(a){try{return""!== +a?JSON.parse(a):null}catch(w){throw Error(a);}}function p(a){return a.responseText}function r(a,b){if("function"===typeof a)if(b instanceof Array)for(var d=0;dn.status||304===n.status)b(r(g.type,a));else{var h=Error(n.responseText),k;for(k in a)h[k]=a[k];d(h)}}catch(G){d(G)}}; +u&&null!=g.data?n.send(g.data):n.send()}))},jsonp:function(g){return d(new b(function(b,d){var n=g.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=a.document.createElement("script");a[n]=function(d){k.parentNode.removeChild(k);b(r(g.type,d));delete a[n]};k.onerror=function(){k.parentNode.removeChild(k);d(Error("JSONP request failed"));delete a[n]};null==g.data&&(g.data={});g.url=l(g.url,g.data);g.data[g.callbackKey||"callback"]=n;k.src=h(g.url,g.data);a.document.documentElement.appendChild(k)}))}, +setCompletionCallback:function(a){q=a}}}(window,"undefined"!==typeof Promise?Promise:y),J=function(){var a=[];return{subscribe:a.push.bind(a),unsubscribe:function(b){b=a.indexOf(b);-1=A&&B>=l;){var x=a[A],m=e[l];if(x!==m||f)if(null==x)A++;else if(null==m)l++;else if(x.key===m.key)A++,l++,h(c,x,m,g,p(a,A,d),f,n),f&&x.tag===m.tag&&r(c,v(x),d); +else if(x=a[q],x!==m||f)if(null==x)q--;else if(null==m)l++;else if(x.key===m.key)h(c,x,m,g,p(a,q+1,d),f,n),(f||l=A&&B>=l;){x=a[q];m=e[B];if(x!==m||f)if(null==x)q--;else{if(null!=m)if(x.key===m.key)h(c,x,m,g,p(a,q+1,d),f,n),f&&x.tag===m.tag&&r(c,v(x),d),null!=x.dom&&(d=x.dom),q--;else{if(!w){w=a;var x=q,D={},z;for(z=0;z Date: Sun, 27 Nov 2016 12:17:00 +0000 Subject: [PATCH 05/17] Rephrase 'restrictive interfaces' & 'magic indices' to reflect common concerns --- docs/components.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/components.md b/docs/components.md index bf61a6ee..b7588379 100644 --- a/docs/components.md +++ b/docs/components.md @@ -169,11 +169,11 @@ Be aware that when using ES5 functions, the value of `this` in nested anonymous ### Avoid anti-patterns -Although Mithril is flexible, some code patterns are discouraged: +Try to keep component interfaces generic by default - use custom interfaces when implementation isn't generic. -#### Avoid restrictive interfaces +#### Avoiding restrictive interfaces -A component has a restrictive interface when it exposes only specific properties, under the assumption that other properties will not be needed, or that they can be added at a later time. +A component has a restrictive interface when it is unnecessarily specific in its use of attributes. Custom attributes should be used when a component has a very specific purpose or requires special internal logic, but this often isn't the case - attributes and children should be used where possible. In the example below, the `button` configuration is severely limited: it does not support any events other than `onclick`, it's not styleable and it only accepts text as children (but not elements, fragments or trusted HTML). @@ -188,7 +188,7 @@ var RestrictiveComponent = { } ``` -It's preferable to allow passing through parameters to a component's root node, if it makes sense to do so: +If the required attributes are equivalent to generic DOM attributes, it's preferable to allow passing through parameters to a component's root node, if it makes sense to do so. ```javascript // PREFER @@ -201,7 +201,9 @@ var FlexibleComponent = { } ``` -#### Avoid magic indexes +#### Don't manipulate `children` + +However, if a component is opinionated in how it applies attributes or children, you should switch to using custom attributes. Often it's desirable to define multiple sets of children, for example, if a component has a configurable title and body. @@ -233,7 +235,7 @@ m(Header, [ ]) ``` -The component above makes different children look different based on where they appear in the array. It's difficult to understand the component without reading its implementation. Instead, use attributes as named parameters and reserve `children` for uniform child content: +The component above breaks the assumption that children will be output in the same contiguous format as they are received. It's difficult to understand the component without reading its implementation. Instead, use attributes as named parameters and reserve `children` for uniform child content: ```javascript // PREFER From 2f5fe86cafde5a4a47b834874fd1d333e81bfc48 Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Sun, 27 Nov 2016 12:49:38 +0000 Subject: [PATCH 06/17] Revert & fine-tune wording --- docs/components.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/components.md b/docs/components.md index b7588379..1c6aa8c1 100644 --- a/docs/components.md +++ b/docs/components.md @@ -169,11 +169,11 @@ Be aware that when using ES5 functions, the value of `this` in nested anonymous ### Avoid anti-patterns -Try to keep component interfaces generic by default - use custom interfaces when implementation isn't generic. +Although Mithril is flexible, some code patterns are discouraged: #### Avoiding restrictive interfaces -A component has a restrictive interface when it is unnecessarily specific in its use of attributes. Custom attributes should be used when a component has a very specific purpose or requires special internal logic, but this often isn't the case - attributes and children should be used where possible. +Try to keep component interfaces generic - using `attrs` and `children` directly - unless the component requires special logic to operate on input. In the example below, the `button` configuration is severely limited: it does not support any events other than `onclick`, it's not styleable and it only accepts text as children (but not elements, fragments or trusted HTML). @@ -188,7 +188,7 @@ var RestrictiveComponent = { } ``` -If the required attributes are equivalent to generic DOM attributes, it's preferable to allow passing through parameters to a component's root node, if it makes sense to do so. +If the required attributes are equivalent to generic DOM attributes, it's preferable to allow passing through parameters to a component's root node. ```javascript // PREFER From 1dd341fff5851ec3605189bdac006fa02e4fde69 Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Sun, 27 Nov 2016 12:50:45 +0000 Subject: [PATCH 07/17] Typo --- docs/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/components.md b/docs/components.md index 1c6aa8c1..49360017 100644 --- a/docs/components.md +++ b/docs/components.md @@ -171,7 +171,7 @@ Be aware that when using ES5 functions, the value of `this` in nested anonymous Although Mithril is flexible, some code patterns are discouraged: -#### Avoiding restrictive interfaces +#### Avoid restrictive interfaces Try to keep component interfaces generic - using `attrs` and `children` directly - unless the component requires special logic to operate on input. From b399af1073282f7f89b2dc990aeed4dec7e705eb Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Sun, 27 Nov 2016 15:04:03 +0000 Subject: [PATCH 08/17] Add vnode mutation warning under components documentation --- docs/components.md | 66 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/docs/components.md b/docs/components.md index bf61a6ee..524575f3 100644 --- a/docs/components.md +++ b/docs/components.md @@ -261,7 +261,9 @@ m(BetterHeader, { }) ``` -#### Avoid component factories +#### Define components statically, call them dynamically + +##### Avoid creating component definitions inside views If you create a component from within a `view` method (either directly inline or by calling a function that does so), each redraw will have a different clone of the component. When diffing component vnodes, if the component referenced by the new vnode is not strictly equal to the one referenced by the old component, the two are assumed to be different components even if they ultimately run equivalent code. This means components created dynamically via a factory will always be re-created from scratch. @@ -291,3 +293,65 @@ m.render(document.body, m(Component, {greeting: "hello"})) // calling a second time does not modify DOM m.render(document.body, m(Component, {greeting: "hello"})) ``` + +##### Avoid creating component instances outside views + +Conversely, for similar reasons, if a component instance is created outside of a view, future redraws will perform an equality check on the node and skip it. Therefore component instances should always be created inside views: + +``` +// AVOID +var Counter = { + count: 0, + view: function(vnode) { + return m("div", + m("p", "Count: " + vnode.state.count ), + + m("button", { + onclick: function() { + vnode.state.count++ + } + }, "Increase count") + ) + } +} + +var counter = m(Counter) + +m.mount(document.body, { + view: function(vnode) { + return [ + m("h1", "My app"), + counter + ] + } +}) +``` + +In the example above, clicking the counter component button will increase its state count, but its view will not be triggered because the vnode representing the component shares the same reference, and therefore the render process doesn't diff them. You should always call components in the view to ensure a new vnode is created: + +``` +// Prefer +var Counter = { + count: 0, + view: function(vnode) { + return m("div", + m("p", "Count: " + vnode.state.count ), + + m("button", { + onclick: function() { + vnode.state.count++ + } + }, "Increase count") + ) + } +} + +m.mount(document.body, { + view: function(vnode) { + return [ + m("h1", "My app"), + m(Counter) + ] + } +}) +``` From 2e43bf4f7b81551d00256edc5ccbfd3fa1567894 Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Sun, 27 Nov 2016 15:16:55 +0000 Subject: [PATCH 09/17] Add vnode caching warning under hyperscript documentation --- docs/hyperscript.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/hyperscript.md b/docs/hyperscript.md index af1067e9..e28781d1 100644 --- a/docs/hyperscript.md +++ b/docs/hyperscript.md @@ -408,3 +408,9 @@ var BetterListComponent = { } } ``` + +#### Avoid creating vnodes outside views + +When a redraw encounters a vnode which is strictly equal to the one in the previous render, it will be skipped and its contents will not be updated. While this may seem like an opportunity for performance optimisation, it should be avoided because it prevents dynamic changes in that node's tree - this leads to side-effects such as downstream lifecycle methods failing to trigger on redraw. In this sense, Mithril vnodes are immutable: new vnodes are compared to old ones; mutations to vnodes are not persisted. + +The component documentation contains [more detail and an example of this anti-pattern](components.md#avoid-creating-component-instances-outside-views). From f040bfe47023a4fbdc98ea23e8cd8540aeba529a Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Sun, 27 Nov 2016 15:24:34 +0000 Subject: [PATCH 10/17] Typos --- docs/components.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/components.md b/docs/components.md index 524575f3..116cd38e 100644 --- a/docs/components.md +++ b/docs/components.md @@ -298,7 +298,7 @@ m.render(document.body, m(Component, {greeting: "hello"})) Conversely, for similar reasons, if a component instance is created outside of a view, future redraws will perform an equality check on the node and skip it. Therefore component instances should always be created inside views: -``` +```javascript // AVOID var Counter = { count: 0, @@ -329,8 +329,8 @@ m.mount(document.body, { In the example above, clicking the counter component button will increase its state count, but its view will not be triggered because the vnode representing the component shares the same reference, and therefore the render process doesn't diff them. You should always call components in the view to ensure a new vnode is created: -``` -// Prefer +```javascript +// PREFER var Counter = { count: 0, view: function(vnode) { From c4072b82225d52567eca733226c7180ee7e906ed Mon Sep 17 00:00:00 2001 From: Eugene Marcotte Date: Sun, 27 Nov 2016 16:28:07 -0500 Subject: [PATCH 11/17] Fix tiny spelling error (#1430) --- docs/vnodes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/vnodes.md b/docs/vnodes.md index 97b8d364..9fb23cde 100644 --- a/docs/vnodes.md +++ b/docs/vnodes.md @@ -16,7 +16,7 @@ The first time a virtual DOM tree is rendered, it is used as a blueprint to crea Typically, Virtual DOM trees are then recreated every render cycle, which normally occurs in response to event handlers or to data changes. Mithril *diffs* a vnode tree against its previous version and only modifies DOM elements in spots where there are changes. -It may seem wasteful to recreate vnodes so frequently, but as it turns out, modern Javascript engines can create hundres of thousands of objects in less than a millisecond. On the other hand, modifying the DOM is several orders of magnitude more expensive than creating vnodes. +It may seem wasteful to recreate vnodes so frequently, but as it turns out, modern Javascript engines can create hundreds of thousands of objects in less than a millisecond. On the other hand, modifying the DOM is several orders of magnitude more expensive than creating vnodes. For that reason, Mithril uses a sophisticated and highly optimized virtual DOM diffing algorithm to minimize the amount of DOM updates. Mithril *also* generates carefully crafted vnode data structures that are compiled by Javascript engines for near-native data structure access performance. In addition, Mithril aggressively optimizes the function that creates vnodes as well. From e76bb9678773a4cd77b64fdfbc9e62b7fe0b1629 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 28 Nov 2016 14:43:29 -0500 Subject: [PATCH 12/17] Add link to response detail section (#1434) --- docs/request.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/request.md b/docs/request.md index 173233c1..cbda6b9c 100644 --- a/docs/request.md +++ b/docs/request.md @@ -10,6 +10,7 @@ - [Monitoring progress](#monitoring-progress) - [Casting response to a type](#casting-response-to-a-type) - [Non-JSON responses](#non-json-responses) +- [Retrieving response details](#retrieving-response-details) - [Why JSON instead of HTML](#why-json-instead-of-html) - [Why XMLHttpRequest instead of fetch](#why-xmlhttprequest-instead-of-fetch) From 216b03c4d71c4e32195042c60fb1a9658f164231 Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Tue, 29 Nov 2016 01:17:54 +0000 Subject: [PATCH 13/17] Document array semantics and vnode equality logic in migration guide --- docs/v1.x-migration.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/v1.x-migration.md b/docs/v1.x-migration.md index f23111b1..9fbd3e5a 100644 --- a/docs/v1.x-migration.md +++ b/docs/v1.x-migration.md @@ -17,6 +17,8 @@ - [Accessing route params](#accessing-route-params) - [`m.request`](#mrequest) - [`xlink` namespace required](#xlink-namespace-required) +- [Nested arrays in views](#nested-arrays-in-views) +- [Vnode immutability](#nested-arrays-in-views) --- @@ -243,7 +245,7 @@ m.mount(document.body, { oninit : function(vnode) { // ... }, - + view : function(vnode) { // Use vnode.state instead of ctrl // Use vnode.attrs instead of options @@ -492,3 +494,15 @@ m("svg", m("image[xlink:href='image.gif']") ) ``` + +*** + +## Nested arrays in views + +Arrays now represent [fragments](fragments.md), which are structurally significant in v1.x virtual DOM. Whereas nested arrays in v0.2.x would be flattened into one continuous list of virtual nodes for the purposes of diffing, v1.x preserves the array structure - the children of any given array are not considered siblings of those of adjacent arrays. + +*** + +## Vnode immutability + +If a vnode is strictly equal to the vnode occupying its place in the last draw, v1.x will skip that part of the tree without checking for mutations or triggering any lifecycle methods in the subtree. The component documentation contains [more detail on this issue](components.md#avoid-creating-component-instances-outside-views). From 32e7518b6f8b177e096c2791a4ac558fd85b3f11 Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Tue, 29 Nov 2016 01:21:32 +0000 Subject: [PATCH 14/17] Typo / better heading --- docs/v1.x-migration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/v1.x-migration.md b/docs/v1.x-migration.md index 9fbd3e5a..8a24e2d1 100644 --- a/docs/v1.x-migration.md +++ b/docs/v1.x-migration.md @@ -18,7 +18,7 @@ - [`m.request`](#mrequest) - [`xlink` namespace required](#xlink-namespace-required) - [Nested arrays in views](#nested-arrays-in-views) -- [Vnode immutability](#nested-arrays-in-views) +- [Vnode equality checks](#vnode-equality-checks) --- @@ -503,6 +503,6 @@ Arrays now represent [fragments](fragments.md), which are structurally significa *** -## Vnode immutability +## Vnode equality checks If a vnode is strictly equal to the vnode occupying its place in the last draw, v1.x will skip that part of the tree without checking for mutations or triggering any lifecycle methods in the subtree. The component documentation contains [more detail on this issue](components.md#avoid-creating-component-instances-outside-views). From bd38286330014129eff738a7dceb757dc8f57fdc Mon Sep 17 00:00:00 2001 From: Alexander Travov Date: Tue, 29 Nov 2016 17:12:33 +0300 Subject: [PATCH 15/17] Fix broken link in migration docs --- docs/v1.x-migration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/v1.x-migration.md b/docs/v1.x-migration.md index 8a24e2d1..a4d78053 100644 --- a/docs/v1.x-migration.md +++ b/docs/v1.x-migration.md @@ -499,7 +499,7 @@ m("svg", ## Nested arrays in views -Arrays now represent [fragments](fragments.md), which are structurally significant in v1.x virtual DOM. Whereas nested arrays in v0.2.x would be flattened into one continuous list of virtual nodes for the purposes of diffing, v1.x preserves the array structure - the children of any given array are not considered siblings of those of adjacent arrays. +Arrays now represent [fragments](fragment.md), which are structurally significant in v1.x virtual DOM. Whereas nested arrays in v0.2.x would be flattened into one continuous list of virtual nodes for the purposes of diffing, v1.x preserves the array structure - the children of any given array are not considered siblings of those of adjacent arrays. *** From 5f08c278ec9bc0faf0477b41c4b85522cba36cc5 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Tue, 29 Nov 2016 14:38:31 -0800 Subject: [PATCH 16/17] Consistency --- docs/v1.x-migration.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/v1.x-migration.md b/docs/v1.x-migration.md index a4d78053..6f4a415c 100644 --- a/docs/v1.x-migration.md +++ b/docs/v1.x-migration.md @@ -18,7 +18,7 @@ - [`m.request`](#mrequest) - [`xlink` namespace required](#xlink-namespace-required) - [Nested arrays in views](#nested-arrays-in-views) -- [Vnode equality checks](#vnode-equality-checks) +- [`vnode` equality checks](#vnode-equality-checks) --- @@ -495,14 +495,14 @@ m("svg", ) ``` -*** +--- ## Nested arrays in views Arrays now represent [fragments](fragment.md), which are structurally significant in v1.x virtual DOM. Whereas nested arrays in v0.2.x would be flattened into one continuous list of virtual nodes for the purposes of diffing, v1.x preserves the array structure - the children of any given array are not considered siblings of those of adjacent arrays. -*** +--- -## Vnode equality checks +## `vnode` equality checks If a vnode is strictly equal to the vnode occupying its place in the last draw, v1.x will skip that part of the tree without checking for mutations or triggering any lifecycle methods in the subtree. The component documentation contains [more detail on this issue](components.md#avoid-creating-component-instances-outside-views). From 9406c905c0f41e9b064a9b6ba7c47abd474e3821 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Wed, 30 Nov 2016 11:51:10 -0800 Subject: [PATCH 17/17] Travis should lint & bundle before every build (#1441) Linting doesn't break builds though, because @lhorie doesn't want that. --- .travis.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5cac2607..4d118c54 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,12 @@ install: - npm install - npm install @alrra/travis-scripts@^3.0.1 +# Lint (but don't fail build) before running tests +before_script: npm run lint || true + +# Run more than just npm test +script: npm run build && npm test + # After a successful build create bundles & commit back to the repo after_success: - | @@ -29,8 +35,7 @@ after_success: --path-encrypted-key "./.deploy.enc" # Build & commit changes - $(npm bin)/commit-changes --commands "npm run build" \ - --commit-message "Bundled output for commit $TRAVIS_COMMIT [skip ci]" \ + $(npm bin)/commit-changes --commit-message "Bundled output for commit $TRAVIS_COMMIT [skip ci]" \ --branch "$BRANCH" env: