Mais conteúdo relacionado Semelhante a 2016 stop writing javascript frameworks by Joe Gregorio (20) Mais de David Zapateria Besteiro (6) 2016 stop writing javascript frameworks by Joe Gregorio2. ● I am employed by Google
● This talk does not represent the opinion of
Google
Caveats
3. ● Code is for exposition purposes only.
Caveats
5. ● Open Source https://skia.org
● 2D Graphics Library
○ CPU
○ GPU
○ PDF
About Skia
7. ● Hidden Gems
○ PathOps
https://skia.org/dev/present/pathops
○ SkNx https://skia.org/dev/contrib/simd
About Skia
8. ● Infrastructure
○ Run the Tests
○ Tools for Analysis
■ 500,000 Images/Commit
■ 260,000 Perf Metrics/Commit
About Me
9. ● Go
● Polymer
● Google Compute Engine
● Open Source
○ https://skia.googlesource.com/buildbot/
About Skia Infra
15. ● Build fast
● Iterate quickly
● Maintain robustly
● Do things at scale
Context
18. Things I didn't say
● Stop innovating.
● Stop using Javascript libraries.
● Stop using tools.
● I have all the answers.
35. <LAYER ID=layer1 TOP=20pt LEFT=5pt BGCOLOR="#CC00EE"
WIDTH=200>
<H1>Layer 1</H1>
<P>Lots of content for this layer.</P>
<IMG SRC=violets.jpg align=right>
<P>Content for layer 1.</P>
<P>More Content for layer 1.</P>
</LAYER>
http://web.archive.org/web/20040929103224/http://developer.netscape.com/docs/manuals/communicator/dynhtml/index.htm
36. There was no consistent model for
interacting with the browser.
63. HTML Imports
● <link rel="import" href="">
● Oddly slightly contentious.
● Brilliant for code organization, keep HTML,
CSS, and JS together in one file.
64. HTML Imports
● Are de-dup'd
● Can contain anything an HTML file can
contain (HTML, CSS, JS)
● Scripts are executed in the context of the
window that imported them
74. Context = function() {
this.doc = (document.currentScript ||document._currentScript).ownerDocument;
};
Context.prototype. import = function(id) {
return document.importNode(this.doc.querySelector( '#'+id).content, true);
};
util.js
75. <template id=t>
<div class=greeting>
Hello World!
</div>
</template>
<script>
(function() {
var ctx = new Context();
document.body.appendChild(ctx. import('t'));
})();
</script>
bit.ly/zf-import-context
import.html
76. Custom Elements
● Oddly uncontentious
● Only talking about creating new elements,
not subclassing existing elements.
77. var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {
this.textContent = 'Hello World!';
};
proto.addMoreText = function(s) {
this.textContent = this.textContent + s;
};
document.registerElement('hello-element', {
prototype: proto
});
78. var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {
this.textContent = 'Hello World!';
};
proto.addMoreText = function(s) {
this.textContent = this.textContent + s;
};
document.registerElement('hello-element', {
prototype: proto
});
79. var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {
this.textContent = 'Hello World!';
};
proto.addMoreText = function(s) {
this.textContent = this.textContent + s;
};
document.registerElement('hello-element', {
prototype: proto
});
81. var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {
this.textContent = 'Hello World!';
};
proto.addMoreText = function(s) {
this.textContent = this.textContent + s;
};
document.registerElement('hello-element', {
prototype: proto
});
82. var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {
this.textContent = 'Hello World!';
};
proto.addMoreText = function(s) {
this.textContent = this.textContent + s;
};
document.registerElement('hello-element', {
prototype: proto
});
84. Context = function() {
this.doc = (document.currentScript ||document._currentScript).ownerDocument;
};
Context.prototype. import = function(id) {
return document.importNode(this.doc.querySelector( '#'+id).content, true);
};
function newElement(name, proto) {
var ep = Object.create(HTMLElement.prototype);
Object.keys(proto).forEach( function(key) {
ep[key] = proto[key];
});
document.registerElement(name, {prototype : ep});
}
util.js
85. Context = function() {
this.doc = (document.currentScript||document._currentScript).ownerDocument;
};
Context.prototype. import = function(id) {
return document.importNode( this.doc.querySelector('#'+id).content, true);
};
function newElement(name, proto) {
var ep = Object.create(HTMLElement.prototype);
Object.keys(proto).forEach(function(key) {
ep[key] = proto[key];
});
document.registerElement(name, {prototype: ep});
}
util.js
89. <template id=t>
<button>Hide</button>
</template>
<script>
(function() {
var ctx = new Context();
newElement('toggle-next', {
createdCallback: function() {
this.appendChild(ctx.import('t'));
this.button = this.querySelector('button');
this.button.addEventListener('click',
this._buttonClick.bind(this));
},
_buttonClick: function() {
var current = this.nextElementSibling.style.visibility;
if (current == 'collapse') {
this.nextElementSibling.style.visibility= 'visible';
this.button.innerText = 'Hide';
} else {
this.nextElementSibling.style.visibility= 'collapse';
this.button.innerText = 'Show';
}
}
})
})();
</script>
90. <template id=t>
<button>Hide</button>
</template>
<script>
(function() {
var ctx = new Context();
newElement('toggle-next', {
createdCallback: function() {
this.appendChild(ctx.import('t'));
this.button = this.querySelector('button');
this.button.addEventListener('click',
this._buttonClick.bind(this));
},
_buttonClick: function() {
var current = this.nextElementSibling.style.visibility;
if (current == 'collapse') {
this.nextElementSibling.style.visibility = 'visible';
this.button.innerText = 'Hide';
} else {
this.nextElementSibling.style.visibility = 'collapse';
this.button.innerText = 'Show';
}
}
})
})();
</script>
91. <template id=t>
<button>Hide</button>
</template>
<script>
(function() {
var ctx = new Context();
newElement('toggle-next', {
createdCallback: function() {
this.appendChild(ctx.import('t'));
this.button = this.querySelector('button');
this.button.addEventListener('click',
this._buttonClick.bind(this));
},
_buttonClick: function() {
var current = this.nextElementSibling.style.visibility;
if (current == 'collapse') {
this.nextElementSibling.style.visibility= 'visible';
this.button.innerText = 'Hide';
} else {
this.nextElementSibling.style.visibility= 'collapse';
this.button.innerText = 'Show';
}
}
})
})();
</script>
92. <template id=t>
<button>Hide</button>
</template>
<script>
(function() {
var ctx = new Context();
newElement('toggle-next', {
createdCallback: function() {
this.appendChild(ctx.import('t'));
this.button = this.querySelector('button');
this.button.addEventListener('click',
this._buttonClick.bind(this));
},
_buttonClick: function() {
var current = this.nextElementSibling.style.visibility;
if (current == 'collapse') {
this.nextElementSibling.style.visibility = 'visible';
this.button.innerText = 'Hide';
} else {
this.nextElementSibling.style.visibility = 'collapse';
this.button.innerText = 'Show';
}
}
})
})();
</script>
93. <template id=t>
<button>Hide</button>
</template>
<script>
(function() {
var ctx = new Context();
newElement('toggle-next', {
createdCallback: function() {
this.appendChild(ctx.import('t'));
this.button = this.querySelector('button');
this.button.addEventListener('click',
this._buttonClick.bind(this));
},
_buttonClick: function() {
var current = this.nextElementSibling.style.visibility;
if (current == 'collapse') {
this.nextElementSibling.style.visibility= 'visible';
this.button.innerText = 'Hide';
} else {
this.nextElementSibling.style.visibility= 'collapse';
this.button.innerText = 'Show';
}
}
})
})();
</script>
94. <template id=t>
<button>Hide</button>
</template>
<script>
(function() {
var ctx = new Context();
NewElement('toggle-next', {
createdCallback: function() {
this.appendChild(ctx.import('t'));
this.button = this.querySelector('button');
this.button.addEventListener('click',
this._buttonClick.bind(this));
},
_buttonClick: function() {
var current = this.nextElementSibling.style.visibility;
if (current == 'collapse') {
this.nextElementSibling.style.visibility = 'visible';
this.button.innerText = 'Hide';
} else {
this.nextElementSibling.style.visibility = 'collapse';
this.button.innerText = 'Show';
}
}
})
})();
</script>
95. <template id=t>
<button>Hide</button>
</template>
<script>
(function() {
var ctx = new Context();
newElement('toggle-next', {
createdCallback: function() {
this.appendChild(ctx.import('t'));
this.button = this.querySelector('button');
this.button.addEventListener('click',
this._buttonClick.bind(this));
},
_buttonClick: function() {
var current = this.nextElementSibling.style.visibility;
if (current == 'collapse') {
this.nextElementSibling.style.visibility= 'visible';
this.button.innerText = 'Hide';
} else {
this.nextElementSibling.style.visibility= 'collapse';
this.button.innerText = 'Show';
}
}
})
})();
</script>
100. <!DOCTYPE html>
<html>
<head>
<script src="webcomponents.js"></script>
<script src="util.js"></script>
<link rel="import" href="toggle.html">
</head>
<body>
<toggle-next></toggle-next>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi dignissim,
nisi non rhoncus condimentum, felis ante porta eros, ut tincidunt odio nisl
a libero.
</p>
</body>
</html>
bit.ly/zf-toggle
101. So how did this work?
Adjacency in the DOM tree.
117. <sort-stuff data-target="#sortable">
<button data-key=pop>Sort on Population</button>
<button data-key=density>Sort on Density</button>
<button data-key=change>Sort on % Change</button>
</sort-stuff>
<ul id=sortable>
<li data-pop=8.4 data-density=27000 data-change=3.86>New York</li>
<li data-pop=3.9 data-density=8092 data-change=3.59>Los Angeles</li>
<li data-pop=2.7 data-density=11842 data-change=0.99>Chicago</li>
<li data-pop=2.2 data-density=3501 data-change=6.63>Houston</li>
<li data-pop=1.5 data-density=11379 data-change=2.25>Philadelphia</li>
</ul>
118. <sort-stuff data-target="#sortable">
<button data-key=pop>Sort on Population</button>
<button data-key=density>Sort on Density</button>
<button data-key=change>Sort on % Change</button>
</sort-stuff>
<ul id=sortable>
<li data-pop=8.4 data-density=27000 data-change=3.86>New York</li>
<li data-pop=3.9 data-density=8092 data-change=3.59>Los Angeles</li>
<li data-pop=2.7 data-density=11842 data-change=0.99>Chicago</li>
<li data-pop=2.2 data-density=3501 data-change=6.63>Houston</li>
<li data-pop=1.5 data-density=11379 data-change=2.25>Philadelphia</li>
</ul>
119. <sort-stuff data-target="#sortable">
<button data-key=pop>Sort on Population</button>
<button data-key=density>Sort on Density</button>
<button data-key=change>Sort on % Change</button>
</sort-stuff>
<ul id=sortable>
<li data-pop=8.4 data-density=27000 data-change=3.86>New York</li>
<li data-pop=3.9 data-density=8092 data-change=3.59>Los Angeles</li>
<li data-pop=2.7 data-density=11842 data-change=0.99>Chicago</li>
<li data-pop=2.2 data-density=3501 data-change=6.63>Houston</li>
<li data-pop=1.5 data-density=11379 data-change=2.25>Philadelphia</li>
</ul>
120. <sort-stuff data-target="#sortable">
<button data-key=pop>Sort on Population</button>
<button data-key=density>Sort on Density</button>
<button data-key=change>Sort on % Change</button>
</sort-stuff>
<ul id=sortable>
<li data-pop=8.4 data-density=27000 data-change=3.86>New York</li>
<li data-pop=3.9 data-density=8092 data-change=3.59>Los Angeles</li>
<li data-pop=2.7 data-density=11842 data-change=0.99>Chicago</li>
<li data-pop=2.2 data-density=3501 data-change=6.63>Houston</li>
<li data-pop=1.5 data-density=11379 data-change=2.25>Philadelphia</li>
</ul>
121. <sort-stuff data-target="#sortable">
<button data-key=pop>Sort on Population</button>
<button data-key=density>Sort on Density</button>
<button data-key=change>Sort on % Change</button>
</sort-stuff>
<ul id=sortable>
<li data-pop=8.4 data-density=27000 data-change=3.86>New York</li>
<li data-pop=3.9 data-density=8092 data-change=3.59>Los Angeles</li>
<li data-pop=2.7 data-density=11842 data-change=0.99>Chicago</li>
<li data-pop=2.2 data-density=3501 data-change=6.63>Houston</li>
<li data-pop=1.5 data-density=11379 data-change=2.25>Philadelphia</li>
</ul>
124. _clickHandler: function(e) {
var key = e.target.dataset.key;
if (!key) {
return;
}
var target = document.querySelector(this.dataset.target);
var elements = [];
var children = target.children;
for (var i=0; i<children.length; i++) {
var ele = children[i];
elements.push({
value: +ele.dataset[key],
node: ele,
});
}
elements.sort(function(x, y) {
return (x.value == y.value ? 0 : (x.value < y.value ? 1 : -1));
});
elements.forEach(function(i) {
target.appendChild(i.node);
});
},
125. _clickHandler: function(e) {
var key = e.target.dataset.key;
if (!key) {
return;
}
var target = document.querySelector(this.dataset.target);
var elements = [];
var children = target.children;
for (var i=0; i<children.length; i++) {
var ele = children[i];
elements.push({
value: +ele.dataset[key],
node: ele,
});
}
elements.sort(function(x, y) {
return (x.value == y.value ? 0 : (x.value < y.value ? 1 : -1));
});
elements.forEach(function(i) {
target.appendChild(i.node);
});
},
126. _clickHandler: function(e) {
var key = e.target.dataset.key;
if (!key) {
return;
}
var target = document.querySelector(this.dataset.target);
var elements = [];
var children = target.children;
for (var i=0; i<children.length; i++) {
var ele = children[i];
elements.push({
value: +ele.dataset[key],
node: ele,
});
}
elements.sort(function(x, y) {
return (x.value == y.value ? 0 : (x.value < y.value ? 1 : -1));
});
elements.forEach(function(i) {
target.appendChild(i.node);
});
},
127. _clickHandler: function(e) {
var key = e.target.dataset.key;
if (!key) {
return;
}
var target = document.querySelector(this.dataset.target);
var elements = [];
var children = target.children;
for (var i=0; i<children.length; i++) {
var ele = children[i];
elements.push({
value: +ele.dataset[key],
node: ele,
});
}
elements.sort(function(x, y) {
return (x.value == y.value ? 0 : (x.value < y.value ? 1 : -1));
});
elements.forEach(function(i) {
target.appendChild(i.node);
});
},
129. ● sort-stuff has 'data-target' [Attribute] that selects [DOM Structure] the element
to sort.
● The target children [DOM Structure] have data attributes [Attribute] that
elements are sorted on.
● sort-stuff registers for a 'click' [Events] from its children [DOM Structure].
● sort-stuff children [DOM Structure] have data attributes [Attribute] that
determine how the target children will be sorted.
Surfaces Used
130. ● sort-stuff doesn't care what its children are, only that they generate 'click'
events and the 'click' generating elements have the 'data-key' attributes.
● sort-stuff doesn't care what the elements found at data-target are, only that it
has children that have data-"key" attributes.
Only Surfaces Are Used
131. ● Change the children of <sort-stuff>
● Change the children of sort-stuff.data-target.
Only Surfaces Are Used
132. <sort-stuff data-target="#sortable">
<p><input type=radio name=sort data-key=pop /> Population</p>
<p><input type=radio name=sort data-key=density /> Density</p>
<p><input type=radio name=sort data-key=change /> % Change</p>
<sort-stuff>
<table>
<tbody id=sortable>
<tr data-pop=8.4 data-density=27000 data-change=3.86><td>New York</td></tr>
<tr data-pop=3.9 data-density=8092 data-change=3.59><td>Los Angeles</td></tr>
<tr data-pop=2.7 data-density=11842 data-change=0.99><td>Chicago</td></tr>
<tr data-pop=2.2 data-density=3501 data-change=6.63><td>Houston</td></tr>
<tr data-pop=1.5 data-density=11379 data-change=2.25><td>Philadelphia</td></tr>
</tbody>
</table>
140. <template id=t>
<div>
<p><a href="{{ url }}">{{ foo.bar.baz }} {{ quux }}</a>!</p>
<!--
Loop over arrays. Use data attributes of data-repeat-[name]="{{ x.y.z }}"
and reference the values iterated over using {{ [name] }}.
For arrays the 'i' state variable is also set.
-->
<ul data-repeat-num="{{ list }}">
<li>{{ num }} {{ i }}</li>
</ul>
<!--
Loop over Objects. For objects the 'key' state variable is also set.
-->
<ul data-repeat-o="{{ anobj }}">
<li>{{ key }}={{ o.name }}</li>
</ul>
</div>
</template>
141. var clone = ctx.import('t');
Expand(clone, data);
document.body.appendChild(clone);
142. Extra Benefits
● Enabling mix and match (our use of D3.js).
● Better than native. (support and styling).
○ Ever tried to style a checkbox?
○ details/summary
■ http://caniuse.com/#feat=details
147. There are dozens of us!
● You (probably) don't need a JavaScript framework
https://slack-files.com/T03JT4FC2-F151AAF7A-13fe6f98da
150. ● http://webcomponents.org/polyfills/
○ You only need webcomponents-lite.js for all the content in this slide
deck.
● http://bitworking.org/news/2014/05/zero_framework_manifesto
○ The rant that launched it all.
● http://vanilla-js.com/
151. But what about React Native?
“learn once, write anywhere.“
https://en.wikipedia.org/wiki/List_of_platform-independent_GUI_libraries