A Deep Look at Angular Elements

A Deep Look at Angular Elements

15934fa2aa7b2ce21f091e9b7cffa856?s=128

Manfred Steyer

May 01, 2019
Tweet

Transcript

  1. @ManfredSteyer A Deep Look at Angular Elements Manfred Steyer SOFTWAREarchitekt.at

    ManfredSteyer
  2. @ManfredSteyer ✓ Commodore 64 ✓ 1982 ✓ ~ 1 MHz

    ✓ 64 KB RAM ✓ Disks with 170 KB
  3. @ManfredSteyer Version with two cores ;-) Challenge: Resources!

  4. @ManfredSteyer Long Time Maintain- ability Maintain + Extend for 10

    +/- yrs
  5. @ManfredSteyer There are milk products lasting longer than some JavaScript

    frameworks
  6. @ManfredSteyer Web Components

  7. @ManfredSteyer Contents • Web Components and Angular Elements • Polyfills

    • Dynamically adding Web Components • Loading external Web Components • Zone-less Change Detection • Content Projection and Slot API • Bonus: Using existing Web Components with Angular
  8. @ManfredSteyer Didactics • Presentations • Live-Coding • Labs

  9. @ManfredSteyer Labs • Regular labs: You just need a browser

    (Stackblitz) • Bonus labs for later: You need a local environment
  10. @ManfredSteyer About me… • Manfred Steyer • SOFTWAREarchitekt.at • Angular

    Trainings and Consultancy • Google Developer Expert (GDE) • Trusted Angular Collaborator Page ▪ 10 Manfred Steyer Public: Selected European Cities In-House: everywhere http://www.softwarearchitekt.at
  11. @ManfredSteyer Web Components and Angular Elements

  12. @ManfredSteyer Web Components: Framework independent components

  13. @ManfredSteyer Umbrella term for several standards

  14. @ManfredSteyer Standards behind Web Components Templates Shadow DOM Custom Elements

    Omnipresent in Angular Baked-in: @Component(encapsulation: …) Angular Elements
  15. @ManfredSteyer Angular Elements @NgModule({ imports: [BrowserModule], declarations: [MyComponent], entryComponents: [MyComponent]

    }) export class AppModule { }
  16. @ManfredSteyer Angular Elements @NgModule({ imports: [BrowserModule], declarations: [MyComponent], entryComponents: [MyComponent]

    }) export class MyModule { }
  17. @ManfredSteyer Angular Elements @NgModule({ imports: [BrowserModule], declarations: [MyComponent], entryComponents: [MyComponent]

    }) export class MyModule { constructor(private injector: Injector) { } }
  18. @ManfredSteyer Angular Elements @NgModule({ imports: [BrowserModule], declarations: [MyComponent], entryComponents: [MyComponent]

    }) export class MyModule { constructor(private injector: Injector) { const MyElement = createCustomElement( MyComponent, { injector: this.injector }); customElements.define('my-element', MyElement); } }
  19. @ManfredSteyer Using an Angular Element <my-element></my-element>

  20. @ManfredSteyer DEMO

  21. @ManfredSteyer Use the CUSTOM_ELEMENTS_SCHEMA @NgModule({ […], schemas: [ CUSTOM_ELEMENTS_SCHEMA ]

    }) export class AppModule { }
  22. @ManfredSteyer All this can be polyfilled down to IE11 (more

    or less)
  23. @ManfredSteyer Distribution

  24. @ManfredSteyer Polyfill

  25. @ManfredSteyer Selected Polyfills loader •Templates •Custom Elements •Shadow DOM es5-adapter

    •For browsers that DO support custom elements
  26. @ManfredSteyer DEMO

  27. @ManfredSteyer LAB https://tinyurl.com/elements-labs

  28. @ManfredSteyer Alternative to es5-adapter: Differential Loading CLI >= 8 ES

    2015+ ES 5
  29. @ManfredSteyer 3 Steps 1. browserlist file: Add ES 5 browsers

    → e. g. IE9-11 2. tsconfig.json: Set target to ES2015 → "target":"ES2015" 3. Create a production build → ng build --prod
  30. @ManfredSteyer

  31. @ManfredSteyer How can browser decide? <script src="main-es5.js" nomodule></script> <script src="main-es2015.js"

    type="module"></script>
  32. @ManfredSteyer Shadow DOM

  33. @ManfredSteyer Angular & Shadow DOM • Baked-in • Default: Emulation

    • @Component({ encapsulation: ViewEncapsulation.Emulated }) • Shadow DOM (v0) • @Component({ encapsulation: ViewEncapsulation.Native }) • Shadow DOM (v1) • @Component({ encapsulation: ViewEncapsulation.ShadowDom }) • Can be turned off: • @Component({ encapsulation: ViewEncapsulation.None })
  34. @ManfredSteyer DEMO

  35. @ManfredSteyer Dynamically adding custom elements

  36. @ManfredSteyer Adding Custom Elements const elm = document.createElement('my-element'); elm.setAttribute(…); elm['propertyName']

    = …; elm.addEventListener(…); otherElement.appendChild(elm);
  37. @ManfredSteyer DEMO

  38. @ManfredSteyer LAB https://tinyurl.com/elements-labs

  39. @ManfredSteyer Loading External Elements

  40. @ManfredSteyer Simplest Script Loader on Earth const script = document.createElement('script');

    script.src = 'assets/external-dashboard-tile.bundle.js‘; document.body.appendChild(script);
  41. @ManfredSteyer DEMO

  42. @ManfredSteyer LAB https://tinyurl.com/elements-labs

  43. @ManfredSteyer Skrinking your Bundles

  44. @ManfredSteyer How to deal with bundle size • Compiling UI-Code

    down with Ivy • Ivy integration for Elements is not part of Angular 8.0 • Sharing dependencies with ngx-build-plus • More: • See my yesterday’s talk (should be on youtube soon) • Bonus Labs (Director’s Cut)
  45. @ManfredSteyer Zone-less Change Detection

  46. @ManfredSteyer Why zone.js? • Used by Angular's changed detection •

    Patches each browser event • Notifies Angular after each event handler
  47. @ManfredSteyer Why not zone.js? • >100 KB (>10 KB gzipped)

    • Awkward to force consumers of our web components to load zone.js • Issues with native async/await (>=ES 2017)
  48. @ManfredSteyer How to exclude it? platformBrowserDynamic().bootstrapModule(AppModule, {ngZone: 'noop'})

  49. @ManfredSteyer Consequences • Manual Change Detection • Change Detection via

    Observables
  50. @ManfredSteyer DEMO

  51. @ManfredSteyer Content Projection & Slot API (Shadow DOM)

  52. @ManfredSteyer Panel

  53. @ManfredSteyer Implementation <div id="tab"> <h2>{{title}}</h2> <div id="content"> <slot></slot> </div> </div>

  54. @ManfredSteyer Implementation <div id="tab"> <h2>{{title}}</h2> <div id="content"> <slot></slot> <div class="small">

    <slot name="footer"></slot> </div> </div> </div>
  55. @ManfredSteyer Calling a Tab <my-tab title="Page 1"> Lorem <b>ipsum</b>, dolor

    <i>sit</i> amet … <div slot="footer">Some <b>extra</b> info</div> </my-tab>
  56. @ManfredSteyer Slot API • ShadowDOM v1 • ViewEncapsulation.ShadowDom

  57. @ManfredSteyer DEMO

  58. @ManfredSteyer LAB https://tinyurl.com/elements-labs

  59. @ManfredSteyer Bonus: Using Existing Custom Elements

  60. @ManfredSteyer You can databind to any Custom Element <custom-checkbox [checked]="expertMode"

    (changed)="expertMode = $event.detail"> </custom-checkbox>
  61. @ManfredSteyer Two-Way-Databinding is more complicated <custom-checkbox [(checked)]="expertMode"> </custom-checkbox>

  62. @ManfredSteyer Convention for Two-Way-Databinding <custom-checkbox [checked]="expertMode" (checkedChange)="expertMode = $event"> </custom-checkbox>

    <custom-checkbox [checked]="expertMode" (changed)="expertMode = $event.detail"> </custom-checkbox> Bridge the gap with directives!
  63. @ManfredSteyer DEMO

  64. @ManfredSteyer LAB https://tinyurl.com/elements-labs

  65. @ManfredSteyer Summary Polyfills & Custom_Element_Schema Shadow DOM Dynamically Adding Dynamic

    Loading Zone-less Change Detection Content Projection with Slots
  66. @ManfredSteyer Contact and Downloads [mail] manfred.steyer@SOFTWAREarchitekt.at [web] SOFTWAREarchitekt.at [twitter] ManfredSteyer

    d Blog about this stuff Public: Selected European Cities In-House: everywhere http://www.softwarearchitekt.at