Sergio Marin
@highercomve
Who is talking?
Nobody special, my name is Sergio Marin and I'm a web developer just like you.
I Work at uBiome as Technical Lead for Patient Portal
When you hear components do you think about?
Why not?
The main reason is because they break the composition rule
Composition with different frameworks is kinda crazy, you will end up having cross dependencies everywhere.
More on that ...
Those solutions have their own implementation of components, you can't simply add the component in your HTML by only adding the component.
If you create a Vue component you need Vue to run it, if you create a React component you need React to run it and so.
But your browser supports already custom elements, where you can create an HTML tag and to that, you can add logic, listeners, and everything that the web already does and those components will work in any (*) browser.
Web Components
What is a component?
Do we use them now?
Reusable component
Eric Raymond’s 17 Unix Rules
Lets resume 17 rules on 7 rules
- Modularity
- Clarity
- Composition
- Separation
- Simplicity
- Representation
- Extensible
Web Components
are the future
We are going to use it, is inevitable, the idea in this talk is to speak about the underlying technology that maybe will be used in the future by our well know framework.
It would be great to have at least a close idea of how the web platform is evolving , how the browser right now supports web components and how that could change the way we write web applications today.
What do these frameworks offer us?
- Abstraction of the DOM
- Component Life Cycle
- Community
- Data binding
- Routing ...? (maybe...)
Did you know web components are native supported by the Browser?
Current Support
HTML Template
The template element is used to declare fragments of HTML that can be cloned and inserted into the document by script.
In a rendering, the template element represents nothing.
The template contents of a template element are not children of the element itself.
HTML Template
<!doctype html>
<html lang="en">
<head>
<title>Homework</title>
<body>
<template id="template"><p>Smile!</p></template>
<script>
const fragment = document
.getElementById('template')
.content
.cloneNode(true);
document.body.appendChild(fragment);
</script>
</html>
Custom Element
A "Custom Element" defines a new HTML tag which will have all the properties of a native HTML tag
Such as: div, ul, p, a, etc.
Custom Element
The custom elements are the backbone of web components, and they are the ones that offer us all the goodies of the life cycle:
- On creation event
- On mounted event
- On props change event
- On destruction event
There are at least 3 ways of writing custom elements right now.
Custom Element
customElements.define
class LifeCycle2 extends HTMLElement {
static get observedAttributes() { return ['class']; }
constructor () {
super()
console.log('LifeCycle2 created')
}
connectedCallback () {
console.log('LifeCycle2 element added to page.');
}
disconnectedCallback () {
console.log('LifeCycle2 element removed from page..');
}
adoptedCallback () {
console.log('LifeCycle2 element moved to new page.');
}
attributeChangedCallback (attrName, oldValue, newValue) {
console.log('life-cycle element attribute Changed')
console.log('attrName', attrName)
console.log('oldValue', oldValue)
console.log('newValue', newValue)
}
}
customElements.define('life-cycle2', LifeCycle2);
Custom Element
customElements.define with ES5
function LifeCycleEs5 () {
let _ = Reflect.construct(HTMLElement, [], new.target)
console.log('life-cycle-es5 element created but not attached')
return _
}
LifeCycleEs5.prototype = Object.create(HTMLElement.prototype)
LifeCycleEs5.prototype.adoptedCallback = function () {
console.log('life-cycle-es5 element moved to new page.')
}
LifeCycleEs5.prototype.connectedCallback = function () {
console.log('life-cycle-es5 element attached')
}
LifeCycleEs5.prototype.disconnectedCallback = function () {
console.log('life-cycle-es5 element detached')
}
LifeCycleEs5.prototype.attributeChangedCallback = function (attrName, oldValue, newValue) {
console.log('life-cycle-es5 element attribute Changed')
console.log('attributes', attributes)
}
Object.defineProperties(LifeCycleEs5, {
observedAttributes: {
configurable: true,
get: function () { return ['class']; }
}
})
customElements.define('life-cycle-es5', LifeCycleEs5);
Custom Element
document.registerElement (deprecated)
var ComponentProto = Object.create(HTMLElement.prototype);
ComponentProto.createdCallback = function () {
console.log('life-cycle element created but not attached')
};
ComponentProto.attachedCallback = function () {
console.log('life-cycle element attached')
};
ComponentProto.detachedCallback = function () {
console.log('life-cycle element detached')
};
ComponentProto.attributeChangedCallback = function (attrName, oldValue, newValue) {
console.log('life-cycle element attribute Changed')
console.log('attrName', attrName)
console.log('oldValue', oldValue)
console.log('newValue', newValue)
};
document.registerElement('life-cycle', {
prototype: ComponentProto
});
Shadow DOM
Shadow DOM refers to the ability of the browser to include a subtree of DOM elements into the rendering of a document, but not into the main document DOM tree
Shadow DOM
const header = document.createElement('header');
const shadowRoot = header.attachShadow({mode: 'open'});
shadowRoot.innerHTML = '<h1>Hello Shadow DOM</h1>';
// attachShadow DOCS https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow
https://developers.google.com/web/fundamentals/web-components/shadowdom
Shadow DOM
HTML Imports
As its name describes it adds the ability to import an HTML document into another HTML document.
This is perfect for webcomponents as we can define our web components as a file document.
HTML Imports
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.0.2/webcomponents-loader.js"></script>
<link rel="import" href="./giphy-element.html">
<link rel="import" href="./giphy-search.html">
</head>
<body>
<giphy-search api-key="NilCckKtrJq9lDxMICbF7SrJTAN2wABk"></giphy-search>
</body>
</html>
HTML Imports
<script src="./component-builder.js"></script>
<template>
<style>
:host {
display: flex;
flex: auto;
height: 200px;
overflow: hidden;
}
:host ::slotted(img) {
width: auto;
max-height: 200px;
}
</style>
<div class="giphy-search__gif">
<slot></slot>
</div>
</template>
<script>
'use strict';
(function () {
const thisDoc = document.currentScript.ownerDocument;
const GiphyElement = {
src: {
get () {
return this.getAttribute('src') || ''
}
},
template: thisDoc.querySelector('template'),
render () {
return `<img src="${this.src}" />`
},
events: {},
observedAttributes () {
return ['src']
}
}
window.addEventListener('WebComponentsReady', function(e) {
CreateComponent('giphy-element', GiphyElement)
})
})()
</script>
Demo Time!
Thanks!
@highercomve
Slides
https://slides.com/highercomve/web-components
Repo
https://github.com/highercomve/talk-web-components
Back to the browser - web components
By Sergio Marin
Back to the browser - web components
- 804