Upload
fwdays
View
107
Download
0
Embed Size (px)
Citation preview
Mike NorthCTO Levanto Financial
The Road to Native Web Components
INTRODUCTION
WHO’S THIS GUY?
▸ CTO Levanto Financial
▸ frontendmasters.com instructor
▸ Product Guy
▸ I do a lot of JavaScript OSS stuff
▸ I work with Ember & React a lot
DOCUMENT VIEWER
DOCUMENT
INTRO
DO YOU USE WEB COMPONENTS? (YES)
INTRO
THE W3C WEB COMPONENT SPEC
HTML IMPORTS
HTML TEMPLATES
CUSTOM ELEMENTS
SHADOW DOM
INTRO
THE W3C WEB COMPONENT SPEC
HTML IMPORTS
▸ require() for HTML
▸ onload, onerror events
▸ can bring in css/html/js
▸ closure-like js characteristics
INTRO
THE W3C WEB COMPONENT SPEC
CUSTOM ELEMENTS
▸ Custom HTML vocab
▸ Life-cycle
▸ Extensibility
▸ Interoperability (we hope?)
INTRO
THE W3C WEB COMPONENT SPEC
HTML TEMPLATES
▸ Inert HTML in the DOM
▸ Defer loading / rendering
▸ Think: handlebars/jade/etc…
INTRO
THE W3C WEB COMPONENT SPEC
SHADOW DOM
▸ CSS Encapsulation
▸ DOM encapsulation
▸ Each component has own subtree w/in parent page
INTRO
THE W3C WEB COMPONENT SPEC
HTML IMPORTS
HTML TEMPLATES
CUSTOM ELEMENTS
SHADOW DOM
HTML TEMPLATES
<!DOCTYPE html> <html> <head></head> <body>
<template id="something"> <div class="frame"> <h3 class="title">I am a title</h3> <p class="body">I am the body</p> </div> </template> </body> </html>
<template id="something"> <div class="frame"> <h3 class="title">I am a title</h3> <p class="body">I am the body</p> </div> </template>
<template id="something"> <!-- Some style --> <style type="text/css"> .title { font-size: 24px; } </style> <!-- Some behavior --> <script type="text/javascript"> </script> <!-- Some structure and content --> <div class="frame"> <h3 class="title">I am a title</h3> <p class="body">I am the body</p> </div> </template>
// Grab the template var tmpl = document.querySelector(‘#something');
Add the cloned document fragment to the DOM document.body.appendChild( // Clone the template's document fragment document.importNode(tmpl.content, true) );
// Grab the template var tmpl = document.querySelector(‘#something');
Add the cloned document fragment to the DOM document.body.appendChild( // Clone the template's document fragment document.importNode(tmpl.content, true) );
http://codepen.io/TrueNorth/pen/xbyVgL?editors=101
HOW DO FRAMEWORKS HANDLE THIS?
define('examples/templates/index', ['exports'], function (exports) {
'use strict';
exports['default'] = Ember.HTMLBars.template((function() { return { ... buildFragment: function buildFragment(dom) { var el0 = dom.createDocumentFragment(); var el1 = dom.createTextNode("Hello, "); dom.appendChild(el0, el1); var el1 = dom.createElement("strong"); var el2 = dom.createComment(""); dom.appendChild(el1, el2); var el2 = dom.createTextNode(" "); dom.appendChild(el1, el2); var el2 = dom.createComment(""); dom.appendChild(el1, el2); dom.appendChild(el0, el1); var el1 = dom.createTextNode("!"); dom.appendChild(el0, el1); return el0; }, buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { var element0 = dom.childAt(fragment, [1]); var morphs = new Array(2); morphs[0] = dom.createMorphAt(element0,0,0); morphs[1] = dom.createMorphAt(element0,2,2); return morphs; }, statements: [ ["content","firstName",["loc",[null,[1,15],[1,28]]]], ["content","lastName",["loc",[null,[1,29],[1,41]]]] ],
... }; }()));});
LAZY LOADINGLazy engines, JIT template compiler
Webpack chunking
Webpack chunking
SHADOW DOM
APPLICATION DOM
COMPONENT
SHADOW DOM
SHADOW DOM
ENCAPSULATION http://codepen.io/mike-north/pen/OPBNmq?editors=101
SHADOW DOM
CSS ENCAPSULATION
▸ CSS rules do not usually pierce shadow roots
▸ CSS defined inside the shadow root only affects that DOM
▸ :host pseudo-selector for component boundary
▸ ::shadow penetrates shadow roots
▸ /deep/ is deprecated
// Inside shadow root :host { border: 1px solid red; } :host(.hover) { border: 1px solid blue; }
// Outside shadow root #my-thing::shadow p { color: green; }
HOW DO FRAMEWORKS HANDLE THIS?
CSS ENCAPSULATIONember-css-modules ember-component-css
“component styles”
react-css-modules
SHADOW DOM
CONTENT PROJECTION
<textarea name="comment" id="" cols="30" > This is the content of my textarea </textarea>
SHADOW DOM
CONTENT PROJECTION
http://codepen.io/mike-north/pen/emPZMv?editors=1000
CONTENT PROJECTION{{yield}}
2.x <ng-content>, 1.x ng-transclude
this.props.children
HTML IMPORTS
<link rel="import" href="myfile.html" />
<link rel="import" href="myfile.html" />
// Get document fragment of an import var content = document .querySelector('link[rel="import"]') .import;
<link rel="import" href="myfile.html" />
// Get document fragment of an import var content = document .querySelector('link[rel="import"]') .import;
// From a <script> included with the import, // access imported DOM var $abc = document .currentScript .ownerDocument .querySelector('.abc');
HOW DO FRAMEWORKS HANDLE THIS?
IMPORTING COMPONENTS
import MyComponent from 'my-component';
CUSTOM ELEMENTS
CUSTOM ELEMENTS
WHY IS THIS IMPORTANT
▸ Composable building blocks
▸ Life-cycle
▸ Extensibility
▸ Alignment of HTML with mental model of your UI
CUSTOM ELEMENTS
REGISTERING
// Extend a DOM element prototype var MegaButtonProto = Object.create(HTMLButtonElement.prototype);
CUSTOM ELEMENTS
REGISTERING
// Extend a DOM element prototype var MegaButtonProto = Object.create(HTMLButtonElement.prototype);
// Register your new element type var MegaButton = document.registerElement("mega-button", { prototype: MegaButtonProto, extends: "button" });
CUSTOM ELEMENTS
ADDING A TEMPLATE// Template var infoBoxTemplate = document.querySelector('#info-pane-template');
// Extend a DOM element var InfoBoxProto = Object.create(HTMLElement.prototype, { createdCallback: { value: function() { // Create the shadow root this.createShadowRoot().appendChild( // Add the template to the shadow root document.importNode(infoBoxTemplate.content, true) ); } } });
CUSTOM ELEMENTS
ADDING A TEMPLATE// Template var infoBoxTemplate = document.querySelector('#info-pane-template');
// Extend a DOM element var InfoBoxProto = Object.create(HTMLElement.prototype, { createdCallback: { value: function() { // Create the shadow root this.createShadowRoot().appendChild( // Add the template to the shadow root document.importNode(infoBoxTemplate.content, true) ); } } });
// Template var infoBoxTemplate = document.querySelector('#info-pane-template');
// Extend a DOM element var InfoBoxProto = Object.create(HTMLElement.prototype, { createdCallback: { value: function() { // Create the shadow root this.createShadowRoot().appendChild( // Add the template to the shadow root document.importNode(infoBoxTemplate.content, true) ); } } });
CUSTOM ELEMENTS
ADDING A TEMPLATE
HOW DO FRAMEWORKS HANDLE THIS?
CUSTOM ELEMENTSEmber.Component
@Component
React.Component
DEMO
DEMO•Starting Point: http://codepen.io/TrueNorth/pen/PwdLrj •Componentized: http://codepen.io/TrueNorth/pen/xbyqME •HTML Importified: http://codepen.io/TrueNorth/pen/ogawLm