Michael North "The Road to Native Web Components"

Post on 14-Jan-2017

106 views 0 download

Transcript of Michael North "The Road to Native Web Components"

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

THANKS!

michael.l.north@gmail.com @MICHAELLNORTH