Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Web Components – das Ende der SPA-Framework-Ära?

Web Components – das Ende der SPA-Framework-Ära?

Web Components – ein Begriff, den wir immer öfter lesen und lesen werden. Dahinter stehen die Technologien Custom Elements, Shadow DOM und HTML Templates. Zusammen ergeben sie ein natives Komponentenmodell für unseren Browser. Es hilft uns, wiederverwendbare UI-Komponenten zu entwickeln, die wir in jeder App benutzen können. Völlig gleich, ob diese Anwendungen mit einem SPA-Framework entwickelt wurden.

Bedeutet das aber auch, dass wir eigentlich gar kein SPA-Framework mehr benötigen, sondern alles mit Web Components entwickeln können? Dieser spannenden Frage geht Manuel Rauber in diesem Webinar nach anhand einer Real-World-Demo-Applikation, Live-Coding und den Vor- und Nachteilen von Web Components.

Manuel Rauber

May 20, 2020
Tweet

More Decks by Manuel Rauber

Other Decks in Programming

Transcript

  1. Web Components
    Das Ende der SPA-Framework-Ära?
    Manuel Rauber
    @ManuelRauber
    Consultant

    View full-size slide

  2. • The challenge
    • Web Components
    • What are they?
    • How to use them?
    • How to create them?
    Agenda

    View full-size slide

  3. The challenge

    View full-size slide

  4. The challenge
    https://dribbble.com/shots/7169781-Homestay-Web-Design https://dribbble.com/shots/7164322-Food-delivery-Landing-page-design

    View full-size slide


  5. !


    !
    !

    !
    !
    • No semantic
    • Intransparent
    • Changes are difficult
    • Framework dependent

    View full-size slide




  6. !
    !

    !
    !
    !
    +!
    -!
    !
    • Global Scoping
    • Naming conflicts
    • Styling conflicts

    View full-size slide

  7. !


    !
    !

    !
    !
    • Semantic
    • Local Scoping
    • Configuration
    • Bundle Import

    View full-size slide

  8. Web Components

    View full-size slide

  9. Bring a native component model to web instead of having to use frameworks
    Web Components - What are they?
    Custom Element

    Shadow DOM HTML Template

    View full-size slide

  10. Can I use …?
    IE11 Edge Chrome Android Opera Safari iOS
    Custom
    Elements
    ❌ ✅ ✅ ✅ ✅ ⚠ ⚠
    Shadow
    DOM
    ❌ ✅ ✅ ✅ ✅ ✅ ⚠
    HTML
    Templates
    ❌ ✅ ✅ ✅ ✅ ✅ ✅

    View full-size slide

  11. Custom Elements

    View full-size slide

  12. • Create your own HTML tags
    • Lifecycle model (“connected”, “disconnected”, “attribute changed”, “adopted”)
    • Reusable
    • Decouple behavior from the document
    Custom Elements
    !

    View full-size slide

  13. • ES6 Class
    • Inherit from HTMLElement
    or any other HTML element
    • Need to be defined in a
    CustomElementRegistry
    Custom Elements
    class MyRating extends HTMLElement {
    constructor() {
    super();
    console.log('component constructed');
    }
    connectedCallback() {
    console.log('component added to DOM');
    }
    adoptedCallback() {
    console.log('component was moved in DOM');
    }
    disconnectedCallback() {
    console.log('component removed from DOM');
    }
    attributeChangedCallback(name, oldVal, newVal) {
    console.log('a attribute has been changed');
    }
    }
    window.customElements.define('my-rating', MyRating);
    const myRating =
    document.createElement('my-rating');
    document.body.appendChild(myRating);
    !// this moves the node!
    otherElement.appendChild(myRating);
    otherElement.removeChild(myRating);

    View full-size slide

  14. • Static getter observedAttributes
    returns all attributes which
    should be observed
    • All those attributes will trigger
    attributeChangedCallback
    upon a change
    • Does not execute on property
    change!
    Custom Elements - Observed Attributes
    class MyRating extends HTMLElement {
    constructor() {
    super();
    }
    static get observedAttributes() {
    return [ 'value' ];
    }
    attributeChangedCallback(name, oldVal, newVal) {
    if (name !!=== 'value') {
    this.innerHTML = `Rating value ${newVal}`;
    }
    }
    }
    !

    View full-size slide

  15. HTML Templates

    View full-size slide

  16. • HTML tag:
    • Parsed, but not rendered
    • Instantiated via JavaScript
    HTML Templates

    My Image Card!

    Description!
    !
    const template = document.querySelector('template');
    const templateInstance = document.importNode(template.content, true);
    const img = templateInstance.querySelector('img');
    img.setAttribute('src', 'http:!//a-link.com/foo.png');
    document.body.appendChild(templateInstance);

    View full-size slide

  17. • Encapsulates HTML and CSS
    • Isolated DOM: elements within Shadow DOM are not selectable from outside
    • e.g. document.querySelector() won’t return a result
    • Scoped CSS: CSS styles stay within Shadow DOM, no leakage, no bleed-in
    • Composition: declarative, markup-based API, put elements from outside in
    • Simplifies CSS: no conflicts with existing classes and IDs
    • Productivity: app consists of chunks of components instead of one big page
    Shadow DOM
    https://developers.google.com/web/fundamentals/web-components/shadowdom

    View full-size slide

  18. • Shadow host
    DOM node that the
    shadow DOM is attached to
    • Shadow tree
    DOM tree inside shadow DOM
    • Shadow boundary
    Place where the shadow DOM
    ends and the regular DOM begins (“Light DOM”)
    • Shadow root
    Root node of the shadow tree
    Shadow DOM
    document
    shadow
    host
    Document Tree
    Shadow Tree
    shadow
    root
    Shadow boundary

    View full-size slide

  19. • attachShadow() attaches a shadow DOM to any HTML element
    • open and closed mode
    Shadow DOM

    !

    !
    <br/>const shadowHost = document.querySelector('div');<br/>const shadowRoot = shadowHost.attachShadow({ mode: 'open' });<br/>shadowRoot.innerHTML = '<h1>Hello World!!</h1>';<br/>!
    !
    !

    View full-size slide

  20. • open allows access to the HTML element’s shadow DOM
    • closed does not allow access to the HTML element’s shadow DOM
    Shadow DOM
    !// !!...
    shadowHost.attachShadow({ mode: 'open' });
    document.querySelector('div').shadowRoot.querySelector('h1');
    !// !-> [HTMLHeadingElement]
    !// !!...
    shadowHost.attachShadow({ mode: 'closed '});
    document.querySelector('div').shadowRoot.querySelector('h1');
    !// !-> Can not read 'querySelector' of null

    View full-size slide

  21. • A (named) placeholder
    to fill with your own
    markup
    • Basically mixes together
    two DOM trees:
    the shadow & light tree
    Shadow DOM - Slots

    <br/>:host { border: 1px solid black; display: block; }<br/>!

    !
    With Default Content!
    !
    !
    ! !!!

    Unnamed Slot Content!
    !

    Unnamed Slot Content 2!
    Another Slot Content!
    !

    View full-size slide

  22. • Slots emit an event, whenever its content changes: slotchange
    • Get the slotted elements via assignedNodes()
    • https://drafts.csswg.org/css-scoping/#slotted-pseudo
    Shadow DOM - Slots
    const slot = this.shadowRoot.querySelector('slot');
    slot.addEventListener('slotchange', () !=> {
    const assignedNodes = slot.assignedNodes();
    !// Do something with assignedNodes
    });

    View full-size slide

  23. • Styling is done via -tags<br/>• All stylings are local and do not overwrite styles from other shadow DOMs<br/>• No other stylings will bleed into the shadow DOM<br/>Shadow DOM - Styling<br/><template><br/><style><br/>h1 {<br/>color: red;<br/>}<br/>!
    Hello World!!
    !
    const shadowRoot = document.querySelector('div')
    .attachShadow({ mode: 'open' });
    shadowRoot.innerHTML = 'Hello World!!' +
    'h1 { color: red; }!';

    View full-size slide

  24. • Inside shadow DOM
    • :host, :host(), :host-context(), ::slotted()
    • Outside shadow DOM
    • CSS Shadow Parts: ::part()
    • In Discussion: ::theme()
    • Deprecated: >>> (“shadow piercing”)
    Shadow DOM - CSS Selectors

    View full-size slide

  25. • :host: Selects the shadow host element
    • :host(): Selects the shadow host element only, if it has a certain class
    • :host-context(): Selects the shadow host
    element only, if the selector given as the
    function's parameter matches the shadow
    host's ancestor(s) in the place it sits inside
    the DOM hierarchy
    • "::slotted(): Selects a slotted element
    if it matches the selector
    Shadow DOM - CSS Selectors - Inside Shadow DOM
    document
    shadow
    host
    Document Tree
    Shadow Tree
    shadow
    root
    Shadow boundary
    !

    !
    !
    !
    !

    !::slotted(div) {} !
    !
    !

    View full-size slide

  26. Shadow DOM - CSS Selectors - Inside Shadow DOM

    <br/>:host {<br/>display: block;<br/>background-color: blue;<br/>}<br/>:host(.red) { background-color: red; }<br/>:host-context(main) { background-color: yellow; }<br/>!::slotted(article) { background-color: black; }<br/>!

    Before slot!
    Default Slot content!
    After slot!
    !
    !
    !
    !

    !
    !


    Article Content
    !
    !

    View full-size slide

  27. • CSS Shadow Parts (Working Draft): "::part()
    • Allows to selectively expose elements from the shadow tree to the
    outside page for styling purposes
    • https://www.w3.org/TR/css-shadow-parts-1/
    • CSS Shadow Parts (Unofficial Draft): "::theme()
    • Matches all given parts, no matter how deeply nested they are
    • http://tabatkins.github.io/specs/css-shadow-parts/#part-theme
    Shadow DOM - CSS Selectors - Outside Shadow DOM

    View full-size slide

  28. • Allows to selectively expose
    elements from the shadow tree to
    the outside page for styling
    purposes
    Shadow DOM - CSS Selectors - Outside Shadow DOM - ::part

    <br/>header {<br/>background-color: crimson;<br/>}<br/>!

    Style me!
    !
    !
    <br/>my-element.styled!::part(my-header) {<br/>background-color: black;<br/>color: white;<br/>}<br/>!
    !
    !

    View full-size slide

  29. • If a nested Web Component
    will expose an inner Web
    Component’s part, it has to
    use exportparts=“part1 part2 …”
    instead of part=“name”
    Shadow DOM - CSS Selectors - Outside Shadow DOM - ::part
    <br/>my-element!::part(textspan) { color: red; }<br/>!

    exportparts="innerspan textspan”>
    !
    !

    Innerspan!
    Textspan!
    !
    !

    View full-size slide

  30. Importing Web Components

    View full-size slide

  31. • ES6 Import
    • Via Code
    • Deprecated: HTML Import
    Importing Web Components

    !
    !// static import
    import './my-element.js';
    !// dynamic import
    import('./my-element.js')
    .then(!!...);
    !// or lazy-loading via
    const script = document.createElement('script');
    script.src = './my-element.js';
    document.body.appendChild(script);
    const myElement = document.createElement('my-element');
    document.body.appendChild(myElement);

    View full-size slide

  32. CustomElementRegistry

    View full-size slide

  33. • Window global registry for all custom elements
    • API
    • define(): defines a new element
    • get(): returns the constructor of an element (or undefined)
    • whenDefined(): returns a promise which is fulfilled, when the custom
    element is available
    • upgrade(): upgrades an element before it is connected to its shadow
    root
    CustomElementRegistry

    View full-size slide

  34. Take Care!
    A sneak peek into the future

    View full-size slide

  35. Versioning
    My library A
    My library B
    3rd party
    library
    1.0
    3rd party
    library
    2.0
    Application


    defines
    defines
    Uncaught DOMException: Failed to execute ‘define’
    on ‘CustomElementRegistry’: the name “my-web-
    component” has already been used with this
    registry.

    View full-size slide

  36. • If you wish to sync them, then you’ll need to sync them!
    • “Reflecting properties to attributes” or “Reflected DOM Attributes”
    • Helps to keep DOM representation in sync with its JavaScript state
    • Watch out! Properties can hold objects, numbers etc. Attributes only strings

    Attributes vs Properties
    input = document.createElement('input');
    console.log(input.getAttribute('value')); !// null
    input.value = 'one';
    console.log(input.getAttribute('value')); !// null
    input.setAttribute('value', 'two');
    console.log(input.value); !// one

    View full-size slide

  37. • Easy things may require more code
    • Attributes vs Properties
    • addEventListener etc.
    • Bigger component libraries need a strong foundation
    • Think of when and how to render your component
    • There is no virtual DOM like in React or Angular
    • You may need to think of partial DOM updates for bigger components
    Boilerplate & render loops

    View full-size slide

  38. • Forms and Web Components don’t play well yet
    • FormData is not populated
    • does not work
    • Form Participation API aka “Form Attached Controls” is discussion
    • https://github.com/w3c/webcomponents/issues/815
    • https://github.com/w3c/webcomponents/issues/814
    • https://github.com/github/image-crop-element/pull/15
    • https://github.com/axa-ch/patterns-library/issues/1258
    Form Participation API

    View full-size slide

  39. • Already good possibilities to create framework-independent components
    • Decide between view-only and data-controlling Web Components
    • Keep in mind, what is not working yet, but will come in the future
    • Leverage the shadow DOM to encapsulate your Web Components
    • Think of your Web Components API!
    Web Components - Summary

    View full-size slide

  40. • Blog Series: “The Perks & Flaws of Web Components”
    • https://bit.ly/web-components-series
    • Web Components Cheat Sheet
    • Coming soon: https://thinktecture.com/newsletter
    More info about Web Components

    View full-size slide

  41. And… now?
    • Try it out! Fiddle around with Web Components
    • Use them! Include first small Web Components into your application
    • Be prepared! Keep up to date with the development of Web Components
    • Slides & Repo: https://thinktecture.com/manuel-rauber
    • Contact: [email protected] - @manuelrauber

    View full-size slide