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

WebComponents: Native Komponenten fürs Web - ohne und mit Frameworks

WebComponents: Native Komponenten fürs Web - ohne und mit Frameworks

Der aktuelle Single-Page Application und der frühere Windows-Entwickler kennt sie seit „Ewigkeiten”: UI-Komponenten, oder Controls. Durch Kapselung erhalten wir modulare und wiederverwendbare Baukastenelemente, aus denen unsere UI-Anwendungen zusammengesetzt werden. Bisher mussten wir uns im Web eines SPA Frameworks bedienen – ob Angular, ReactJS, Vue.js oder Polymer. Doch keines dieser Frameworks wollte oder konnte so recht mit dem anderen zusammenarbeiten. Dies könnte sich in Zukunft ändern mit WebComponents. Diese beschreiben anhand von Standards wie CustomElements ein Komponentenmodell für das Web und bietet damit erstmal die Möglichkeit, native Komponenten im Browser gänzlich ohne ein Framework oder aber über Framework-Grenzen hinweg einzusetzen.
In dieser Session klären Manuel Rauber und Patrick Jahr wie WebComponents funktionieren, wo die Vorteile und Nachteile liegen – und, vermutlich am spannendsten: sie gehen der Frage in gewohnt praktischer Manier nach, ob WebComponents mit aktuellen Single-Page Application (SPA) Frameworks wie Angular genutzt und erstellt werden können und welche Rolle Ivy dabei spielt. Abgerundet wird das Ganze mit einem Ausblick, wie wir künftig Web-Anwendungen mit Web Components entwickeln könnten. Auf zum nächsten Schritt!

GitHub: https://github.com/thinktecture/angular-days-2019-fall-web-components
GitHub (Chat-Demo): https://github.com/thinktecture-labs/web-components-chat

Manuel Rauber

October 08, 2019
Tweet

More Decks by Manuel Rauber

Other Decks in Programming

Transcript

  1. Web Components:

    Native Komponenten für’s Web
    Ohne und mit Framework
    Manuel Rauber
    @ManuelRauber
    Consultants
    Patrick Jahr
    @jahr_patrick
    Developer

    View Slide

  2. Manuel Rauber
    Speakers
    Patrick Jahr
    [email protected]
    @jahr_patrick
    [email protected]
    @manuelrauber
    https://manuel-rauber.com
    Microsoft MVP

    View Slide

  3. • The challenge
    • Web Components
    • What are they?
    • How to use them?
    • How to create them?
    • Take Care & a peek into the future
    • What about frameworks?!
    • Micro Frontends
    Agenda

    View Slide

  4. The challenge

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  10. DRY

    View Slide

  11. Components
    Components
    Components
    Components

    View Slide

  12. View Slide

  13. !"div>

    View Slide

  14. !"div>


    !"script><br/>!"head><br/><body><br/>!"body><br/>!"html><br/>• No semantic<br/>• Intransparent<br/>• Change are difficult<br/>• Framework dependent<br/>

    View Slide




  15. !"script><br/>!"head><br/><body><br/>!"body><br/>!"html><br/><span id="label">!"span><br/><button id="incButton">+!"button><br/><button id="decButton"!#!"button><br/>!"div><br/>• Global Scoping<br/>• Naming conflicts<br/>• Styling conflicts<br/>

    View Slide

  16. !"my-counter>


    !"script><br/>!"head><br/><body><br/>!"body><br/>!"html><br/>• Semantic<br/>• Local Scoping<br/>• Configuration<br/>• Bundle Import<br/>

    View Slide

  17. Web Components

    View Slide

  18. • Web Components are not a standard, but a collection of 3 technologies
    • Custom Elements
    • HTML templates
    • Shadow DOM
    • (HTML Imports)
    • Bring a native component model to web instead of having to use frameworks
    Web Components - What are they?

    View Slide

  19. Can I use - Custom Elements?

    View Slide

  20. Can I use - Shadow DOM?

    View Slide

  21. Can I use - HTML templates?

    View Slide

  22. Custom Elements

    View Slide

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

    View Slide

  24. • 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 Slide

  25. • 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 Slide

  26. • 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 Slide

  27. • 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 Slide

  28. • 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 Slide

  29. • 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}`;
    }
    }
    }
    !"my-rating>

    View Slide

  30. HTML Templates

    View Slide

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

    My Image Card!"header>
    Description!"p>
    !"template>
    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 Slide

  32. Shadow DOM

    View Slide

  33. • 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 Slide

  34. • 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 Slide

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

    !"head>

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

    View Slide

  36. • 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 Slide

  37. • 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/>!"style><br/><div><br/><slot>!"slot><br/><slot name="another-slot">With Default Content!"slot><br/>!"div><br/>!"template><br/><my-element>!"my-element> !!!* No slot filled !!+<br/><my-element><br/><div>Unnamed Slot Content!"div><br/>!"my-element><br/><my-element><br/><div>Unnamed Slot Content 2!"div><br/><div slot="another-slot">Another Slot Content!"div><br/>!"my-element><br/>

    View Slide

  38. • 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 Slide

  39. • 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/>!"style><br/><h1>Hello World!!"h1><br/>!"template><br/>const shadowRoot = document.querySelector('div')<br/>.attachShadow({ mode: 'open' });<br/>shadowRoot.innerHTML = '<h1>Hello World!!"h1>' +<br/>'<style>h1 { color: red; }!"style>';<br/>

    View Slide

  40. • 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 Slide

  41. • :host: Selects the shadow host element
    Shadow DOM - CSS Selectors - Inside Shadow DOM
    document
    shadow
    host
    Document Tree
    Shadow Tree
    shadow
    root
    Shadow boundary
    !"div>

    View Slide

  42. • :host: Selects the shadow host element
    • :host(): Selects the shadow host element only, if it has a certain class
    Shadow DOM - CSS Selectors - Inside Shadow DOM
    document
    shadow
    host
    Document Tree
    Shadow Tree
    shadow
    root
    Shadow boundary
    !"div>

    View Slide

  43. • :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
    Shadow DOM - CSS Selectors - Inside Shadow DOM
    document
    shadow
    host
    Document Tree
    Shadow Tree
    shadow
    root
    Shadow boundary

    !"div>
    !"body>

    View Slide

  44. • :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
    !"div>

    !-slotted(div) {} !"style><br/><slot name="my-slot">!"slot><br/>!"template><br/>

    View Slide

  45. 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/>!"style><br/><div><br/><p>Before slot!"p><br/><slot>Default Slot content!"slot><br/><p>After slot!"p><br/>!"div><br/>!"template><br/><my-element>!"my-element><br/><my-element class="red">!"my-element><br/><main><br/><my-element>!"my-element><br/>!"main><br/><my-element><br/><article><br/>Article Content<br/>!"article><br/>!"my-element><br/>

    View Slide

  46. • 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 Slide

  47. • 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><br/><div><br/><header part="my-header">Style me!"header><br/>!"div><br/>!"template><br/><style><br/>my-element.styled!-part(my-header) {<br/>background-color: black;<br/>color: white;<br/>}<br/>!"style><br/><my-element>!"my-element><br/><my-element class="styled">!"my-element><br/>

    View Slide

  48. • 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/>!"style><br/><template id="my-element-outer-template"><br/><my-element-inner<br/>exportparts="innerspan textspan”><br/>!"my-element-inner><br/>!"template><br/><template id="my-element-inner-template"><br/><span part="innerspan">Innerspan!"span><br/><span part="textspan">Textspan!"span><br/>!"template><br/><my-element>!"my-element><br/>

    View Slide

  49. Constructable Stylesheets

    View Slide

  50. • W3C: “A collection of interesting ideas”
    • Currently, styling must be specified in each shadow DOM
    • As we know, current web pages have hundreds and thousands CSS styles
    • Long parsing time and memory costs!
    • But most Web Components (or at least within a component library) will use
    the same/shared stylings
    • However, component libraries may update CSS during runtime, which may
    thwart style sheet sharing
    • API allows to create, remove, update, replace style sheet rules
    Constructable Stylesheets - Motivation

    View Slide

  51. Constructable Stylesheets - Demo Code
    const myElementSheet = new CSSStyleSheet();
    class MyElement extends HTMLElement {
    constructor() {
    super();
    const shadowRoot = this.attachShadow({ mode: "open" });
    shadowRoot.adoptedStyleSheets = [myElementSheet];
    }
    connectedCallback() {
    !% Only actually parse the stylesheet when the first instance is connected.
    if (myElementSheet.cssRules.length !. 0) {
    myElementSheet.replaceSync(styleText);
    }
    }
    }
    https://wicg.github.io/construct-stylesheets/

    View Slide

  52. Importing Web Components

    View Slide

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

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

    View Slide

  54. CustomElementRegistry

    View Slide

  55. • 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 Slide

  56. Take Care!
    A sneak peek into the future

    View Slide

  57. 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 Slide

  58. • Problem: Custom Element Registry is a window global object
    • Possible solution currently discussed by W3C
    • Scoped Custom Element Registry
    • https://github.com/w3c/webcomponents/issues/716
    • Current usable solutions
    • Version your HTML tags
    • The host application is the only one loading WCs, even 3rd-party, but this
    could break other Web Components expecting a certain version
    Versioning

    View Slide

  59. • 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 Slide

  60. • Shadow DOM encapsulates the DOM only
    • JavaScript is still global scoped
    • Use common techniques for scoping JavaScript
    • May use the global scope to your advantage for app-wide configurations
    • But global polyfills can cause problems (e.g. if you load zone.js twice)
    JavaScript is still global scoped

    View Slide

  61. • 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 Slide

  62. • There is no built-in template engine, you may be used to from SPA
    frameworks like Angular, React, Vue etc.
    • JavaScript template strings are preferred for better readability
    • Can get complex and unreadable when conditions are used heavily
    No built-in template engine

    View Slide

  63. No built-in template engine - Lit Element example
    get previewTemplate() {
    return html`

    ${this.preview.image
    ? html`: html``
    }

    ${this.preview.title}!"header>
    ${this.preview.description
    ? html`${this.preview.description}!"p>`
    : html``
    }
    !"div>
    !"div>
    `;
    }

    View Slide

  64. • Currently there is no auto completion support for Web Components
    • Stencil tries to solve this by generating TypeScript Definition files
    • VS Code & W3C are discussing possible solutions
    • https://github.com/w3c/webcomponents/issues/776
    • Stencil is currently generating a possible solution with its compiler
    Editor support // type definitions

    View Slide

  65. • There is no standard build process
    • You can use any tool you want, e.g. webpack, parcel, etc.
    • Be aware:
    • CSS post processing
    • Asset management
    Build process // custom asset management

    View Slide

  66. • 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 Slide

  67. • Elements can not escape their stacking context
    • Highly needed for (modal) dialogs, tooltips, right-click menus, select, …
    • Current element does not fit for all use cases
    • Possible workaround: API in the shell
    Stacking UI


    !!!* Will be transformed, but should be a top layer modal dialog !!+
    !"my-modal-dialog>
    !"my-wc-a>
    !"my-wc-b>
    !"body>

    View Slide

  68. • 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 Slide

  69. What about frameworks?!

    View Slide

  70. • Web Components are an uprising good alternative to build frontends
    without frameworks involved
    • But! A lot of stuff is done easier with frameworks, e.g. Form Validation, State
    Handling, Data Management, CSS post processing
    • Why not wrap framework components into Web Components?
    • Angular: Angular Elements, @angular/elements
    • React: Wrap manually or use a community wrapper
    • Vue: Vue Web Components, @vue/web-components
    What about frameworks?!

    View Slide

  71. • Bundle sizes per framework is quite high for small components
    • Possible long loading and parsing times
    • A solution could be:
    • Bundle Web Components without their framework
    • Load the framework in the hosting application
    • Watch out! All Web Components have to use the same framework version
    • Will get better over time with less and less framework involved
    • or frameworks compile to much smaller bundle sizes (e.g. Angular Ivy)
    What about frameworks?! - Bundle Sizes

    View Slide

  72. • Angular Ivy could be used for creating Web Components
    • … as long as you don’t consume other Web Components!
    • Ivy will complain about other Web Components not knowing about
    properties and throw an exception during compilation time



    • Be aware, that Ivy is not yet production ready!
    • Think of removing zone.js and handle everything OnPush
    What about frameworks?! - Angular
    Property ‘propertyName' does not exist on type 'HTMLElement'.

    View Slide

  73. DEMO

    View Slide

  74. Micro Frontends

    View Slide

  75. Micro Frontends
    Feature A
    Feature B
    Application
    Web API
    Web API
    UI
    UI

    View Slide

  76. • Web Component != Micro Frontend
    • A Micro Frontend can be built by multiple Web Components
    • The whole Micro Frontend could be wrapped into a Web Component
    • Micro Frontend(s) are wrapped into a (SPA) shell
    Micro Frontends
    https://example.com
    Micro Frontend
    Dashboard (SPA) Shell

    View Slide

  77. • Eager Loading
    • Server-side composition
    • Build-time integration
    • Lazy Loading
    • iFrames
    • JavaScript
    • Web Components
    Micro Frontends - Composition

    View Slide

  78. • “Does this approach fit my company structure?”
    • SPA-Shell API depending on the composition approach
    • Data exchange / Data API
    • Routing
    • A single Micro Frontend routing is easy
    • A multi Micro Frontend routing is complex
    • Let the user F5 your application!
    • Routing is also a possibility for data exchange
    Micro Frontends - Challenges

    View Slide

  79. Micro Frontends - Challenges
    https://example.com?mf1=/customer/1&mf2=balance/1
    Micro Frontend 1 Micro Frontend 2
    Dashboard

    View Slide

  80. • Interesting possibility to have small customized UIs per feature
    • Think of how you’ll compose Micro Frontends (Micro Frontend Architecture)
    • Think of data exchange in Micro Frontends (if needed)
    • Think of single or multi routing possibilities (let the user F5 your app!)
    • Good for decoupling teams!
    Micro Frontends - Summary

    View Slide

  81. Conclusion

    View Slide

  82. • Web Components help in giving a semantic structure in apps
    • They encapsulate HTML and CSS
    • Improves maintainability and reusability
    • Take care for stuff not working yet (e.g. Form Participation API)
    • SPA Frameworks can help in building Web Components
    • … with the odd of having bigger bundles
    • Micro Frontends help decouple teams
    Web Components - Summary

    View Slide

  83. 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: https://speakerdeck.com/manuelrauber
    • Repository: https://github.com/thinktecture/angular-days-2019-fall-web-components
    • Contact: [email protected], [email protected]

    View Slide