Cory Brown
@uniqname
What Can Web Components Do For Me?
Questions?
-
Can I use them?
-
Why?
-
How?
-
Yes
-
Let me explain, no there is too much. Let me sum up.
-
We'll get to that.
Principles of Componitization
- A single feature
- Self-contained
- Reusable.
Single Feature
Divide apps into problem spaces and group code around these problem spaces. Do not group around technology.
Self-contained
A component must not rely on the inferred existence of a particular state in the application. Any dependency should be provided to the component explicitly.
myElement.configurate = function (config) {
let defaults = {
some: 'thing'
},
settingsAttr = JSON.parse(
myElement.getAttribute('settings')
);
let settings = _.extend({}, defaults, settingsAttr, config);
}
myElement.configurate = function (config) {
let defaults = {
some: 'thing'
},
settingsAttr = JSON.parse(
myElement.getAttribute('settings')
);
let settings = Object.assign({}, defaults, settingsAttr, config);
}
myElement.configurate = function (config) {
let defaults = {
some: 'thing'
},
settingsAttr = myElement.getAttribute('settings') || '{}';
try { settingsAttr = JSON.parse(settingsAttr); }
catch(e) { settingsAttr = {}; }
let settings = Object.assign({}, defaults, settingsAttr, config);
}
Reusable
In order to be reusable, a component must be:
- Repeatable
- Configurable
- Extensible
- Composable
Your code is not reusable if it fails any of these tests.
Repeatable
A component is repeatable if it is easy to create multiple instances of it.
'Instance' in this case does not need to carry with it all the bagage it noramlly does in an OOP context.
Configurable
A component is configurable if it can be easily appropriated for a given task.
Extensible
A component is extensible if additional functionality can be easily and unobtrusively added. This may be in the form of event hooks, lifecycle hooks or an extensibility api.
Composable
A component is composable if it can be easily combined with other components to create new, more complex ones.
Web Components: Proper
HTML Imports
-
-
-
-
Shadow DOM
-
-
-
-
HTML Templates
-
-
-
-
Custom Elements
-
-
-
-
HTML Imports
-
-
-
-
Shadow DOM
-
-
-
-
HTML Templates
-
-
-
-
Custom Elements
-
-
-
-
Polyfill All The Things!
HTML Imports 37K/8K gmin
Shadow DOM 160K/20K gmin
HTML Templates FREE .99
Custom Elements 33K/8K gmin
webcomponents.js 258K/37K gmin
webcomponents-lite.js 78K/16K gmin
Polyfill All The Things!
OMG
IKR
Totes cray!
Roll that beautiful web components footage!!!
HTML Imports
- Include HTML in HTML (it's like HTML inception)
- Package a component as a single consumable.
- Handles dependency resolution
- Handles cyclical dependencies.
- Pairs well with HTTP/2
- Less efficient over HTTP/1.1 without something like vulcanize
HTML Imports
<link rel="stylesheet" href="styles.css" />
<div class="class">
Any valid HTML can go in an HTML Import file.
</div>
<script src="some-file.js"></script>
<link rel="import" href="/path/to/my/web-component.html" />
use it
create it
HTML Imports
HTML Imports
- Replace the <link ="import" /> with a <script>
- Create a template property on the component prototype
- Assign said template property the value of a js generated template element who's contents is the template contents from the import
Living without
HTML Imports
Living without
Shadow DOM
- Encapsulate structural implementations of UI (HTML)
- Encapsulate component styles (prevent "leakage")
- Prevent the external environment from accidentally accessing the internal one.
- Provides a means of composition via a node distribution model
Shadow DOM
Many have seen ShadowDOM as a means of explaining aspects of how the web -- specifically HTML -- works.
<select>
<audio>/<video>
<details>
This is the summary
I'm a detailShadow DOM
let shadowHost = document.querySelector('#needsShadow'),
shadowChild = document.createElement('p');
shadowHost.createShadowRoot();
shadowHost.shadowRoot.append(shadowChild);
Shadow DOM
Shadow DOM
just replace all references to `this.shadowRoot` with `this`.
Living without
Shadow DOM
Living without
HTML Templates
- Content is effectively inert until activated
- Content does not render in the page
- Content is not considered part of the document
- Content produces no side effects (scripts don't run, images don't load, audio doesn't play)
- Template content is "activated" by deep cloning its `content` property -- a read-only documentFragment containing the parsed DOM of the template's contents.
HTML Templates
- Does not have a concept of data binding.
- Is not dynamic
- It's just DOM
HTML Templates
HTML Templates are supported by every major evergreen browser.
It's ridiculously easy to polyfill*
*OK, it's more like a patch as the contents won't be inert, but it's better than writing code around it and we're coding for the future right? RIGHT?
HTML Templates
<template>
<p>Any <strong>HTML</strong>.</p>
<p>Seriously, <em>any</em> <abbr>HTML<abbr></p>
</template>
build it
HTML Templates
var el = document.querySelector(div),
fragment = document.importNode(
document.querySelector('template').content,
true
);
el.appendChild(fragment);
use it
HTML Templates
HTML Templates
- create a `not-a-template` element
- define a `content` property on it with a getter
- return a DOM fragment of the `not-a-template`s innerHTML
Living without
HTML Templates
Custom Elements
Define Custom Semantic Elements as Components
React to lifecycle events
- createdCallback
- attachedCallback
- detachedCallback
- attributeChangedCallback
All other standard events are available to you.
Receive config through attributes (events?)
Expose information via custom events.
Custom Elements
This is where the real power is.
Lifecycle callbacks are RAD!*
*All though technically you don't even need this. Mutation Observers can be made to accomplish the same thing. In fact, this is how Custom Elements is polyfilled.
Custom Elements
const awesomePrototype = Object.create(HTMLElement, {
// assign methods and properties
});
awesomePrototype.createdCallback = function () { ... };
awesomePrototype.attachedCallback = function () { ... };
awesomePrototype.detachedCallback = function () { ... };
awesomePrototype.attributeChangedCallback = function (attrName, prevVal, currVal) { ... };
document.registerElement('awe-some', {
prototype: awesomePrototype
});
built it.
Custom Elements
<awe-some rad="SORT">
<p>Composed DOM</p>
<p>AKA Light DOM</p>
</awe-smome>
use it.
Custom Elements
const awesomePrototype = Object.create(HTMLElement, {
rad: {
get() {
return this.getAttribute('rad');
},
set(val) {
return this.setAttribute('rad', val);
}
}
});
document.registerElement('awe-some', {
prototype: awesomePrototype
});
pro tip: bind attributes to properies with getters/setters.
Custom Elements
Thank You
(loud applause!)
Copy of Native Web Components NOW!!!
By Cory Brown
Copy of Native Web Components NOW!!!
- 1,271