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

Angular Revisited: Tree-shakable Components and Optional NgModules

Angular Revisited: Tree-shakable Components and Optional NgModules

NgModule is arguably one of the most confusing Angular concepts. Using tree-shakable components and dependencies, we will need Angular modules less often or not at all. Tree-shakable components are not available yet, but we can use Single Component Angular Modules to ease the migration path.

Presented at:
- ngVikings conference, May 2019
- Angular In Depth conference, June 2019

Recording of talk from the ngVikings 2019 conference:
https://youtu.be/DA3efofhpq4

Article:
https://dev.to/this-is-angular/angular-revisited-tree-shakable-components-and-optional-ngmodules-36d2

Transcript

  1. Angular Revisited Tree-shakable Components and Optional NgModules

  2. I think NgModule is something that if we didn’t have

    to, we wouldn’t introduce. Back in the day, there was a real need for it. With Ivy and other changes to Angular over the years, we are working towards making those optional. — Igor Minar at AngularConnect 2018
  3. The way NgModule works tends to be confusing to new

    Angular developers. Even if we weren’t to rip it out completely, we would change how it works and simplify things. — Alex Rickabaugh at AngularConnect 2018
  4. Ivy out-of-the-box • Faster builds • Better debugging • Smaller

    bundle size • Instruction set similar to Incremental DOM
  5. Ivy is well-suited for • Micro front-ends • Angular Elements

    • Web apps where Angular is not in control of the entire document
  6. Zoneless change detection with Ivy 1. Change local UI state.

    2. Mark component for check. 3. Schedule change detection cycle. @Component({ selector: 'zippy', template: `<button (click)="onToggle()">{{title}}</button> <div [hidden]="!isExpanded"><ng-content></ng-content></div>`, }) export class ZippyComponent { @Input() title: string; isExpanded = false; onToggle() { this.isExpanded = !this.isExpanded; markDirty(this); } } ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  7. We use Angular modules to • Configure injectors for runtime

    resolving of dependencies • Link declarables when compiling component templates • Bootstrap components as entry points to our applications • Lazy-load application features
  8. Tree-shakable components are • Entry components but tree-shakable by the

    build process • Self-contained and independent from Angular modules • The smallest compilation and code splitting unit for Angular
  9. import { Component, Input, ɵmarkDirty as markDirty } from '@angular/core';

    import { ButtonDirective } from './button.directive'; @Component({ deps: [ ButtonDirective, ], selector: 'zippy', template: `<button ivyButton (ivyClick)="onToggle()">{{title}}</button> <div [hidden]="!isExpanded"><ng-content></ng-content></div>`, }) export class ZippyComponent { @Input() title: string; isExpanded = false; onToggle() { this.isExpanded = !this.isExpanded; markDirty(this); } } Tree-shakable components with proposed component API ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  10. import { Component } from '@angular/core'; import { CapitalizePipe }

    from './capitalize.pipe'; import { ZippyComponent } from './zippy.component'; @Component({ deps: [ CapitalizePipe, ZippyComponent, ], template: `<zippy title="Toggle">{{title | capitalize}}</zippy>`, }) export class AppComponent { title = 'proposed component API'; } Tree-shakable components with proposed component API ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  11. Single component Angular modules • Declare and export only one

    component • Import only the declarables used by their specific component • Are useful for isolated component tests • Can be placed in the same file as their component • The abbreviated form is SCAM ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  12. import { Component, Input, NgModule } from '@angular/core'; import {

    ButtonModule } from './button.directive'; @Component({ selector: 'zippy', template: `<button appButton (appClick)="onToggle()">{{title}}</button> <div [hidden]="!isExpanded"><ng-content></ng-content></div>`, }) export class ZippyComponent { @Input() title: string; isExpanded = false; onToggle() { this.isExpanded = !this.isExpanded; } } @NgModule({ declarations: [ZippyComponent], exports: [ZippyComponent], imports: [ButtonModule], }) export class ZippyModule {} Faux tree-shakable components with SCAMs ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  13. import { Component, NgModule } from '@angular/core'; import { CapitalizeModule

    } from './capitalize.pipe'; import { ZippyModule } from './zippy.component'; @Component({ template: `<zippy title="Toggle">{{title | capitalize}}</zippy>`, }) export class AppComponent { title = 'single component angular modules’; } @NgModule({ declarations: [AppComponent], imports: [ CapitalizeModule, ZippyModule, ], }) export class AppModule {} Faux tree-shakable components with SCAMs ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  14. Component render modules • Exclusively declare dependencies, no Angular module

    imports • Declare all the declarables used by their specific component and additionally the component itself • Can have duplicate declarations between Angular modules • Only work because of a timing issue ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  15. import { Component, Input, NgModule, ɵmarkDirty as markDirty } from

    '@angular/core'; import { ButtonDirective } from './button.directive'; @Component({ selector: 'zippy', template: `<button ivyButton (ivyClick)="onToggle()">{{title}}</button> <div [hidden]="!isExpanded"><ng-content></ng-content></div>`, }) export class ZippyComponent { @Input() title: string; isExpanded = false; onToggle() { this.isExpanded = !this.isExpanded; markDirty(this); } } @NgModule({ declarations: [ ZippyComponent, ButtonDirective, ] }) export class ZippyRenderModule {} Component render modules (Ivy preview with JIT) ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  16. import { Component, NgModule } from '@angular/core'; import { CapitalizePipe

    } from './capitalize.pipe'; import { ZippyComponent } from './zippy.component'; @Component({ template: `<zippy title="Toggle">{{title | capitalize}}</zippy>`, }) export class AppComponent { title = 'component render modules’; } @NgModule({ declarations: [ AppComponent, CapitalizePipe, ZippyComponent, ], }) export class AppRenderModule {} Component render modules (Ivy preview with JIT) ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  17. Feature render modules • Every component exports a nested declarable

    array • A single feature render module per bundle • Angular will flatten the declarable arrays and remove duplicates ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  18. import { Component, Input, ɵmarkDirty as markDirty } from '@angular/core';

    import { ButtonDirective } from './button.directive'; @Component({ selector: 'zippy', template: `<button ivyButton (ivyClick)="onToggle()">{{title}}</button> <div [hidden]="!isExpanded"><ng-content></ng-content></div>`, }) export class ZippyComponent { @Input() title: string; isExpanded = false; onToggle() { this.isExpanded = !this.isExpanded; markDirty(this); } } export const zippyDeps = [ ZippyComponent, ButtonDirective, ]; Feature render modules (Ivy preview with AOT) ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  19. import { Component, NgModule } from '@angular/core'; import { CapitalizePipe

    } from './capitalize.pipe'; import { zippyDeps } from './zippy.component'; @Component({ template: `<zippy title="Toggle">{{title | capitalize}}</zippy>`, }) export class AppComponent { title = 'feature render modules’; } @NgModule({ declarations: [ AppComponent, CapitalizePipe, zippyDeps, ], }) export class AppRenderModule {} Feature render modules (Ivy preview with AOT) ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  20. We use Angular modules to • Configure injectors for runtime

    resolving of dependencies • Link declarables when compiling component templates • Bootstrap components as entry points to our applications • Lazy-load application features
  21. Bootstrapping tree-shakable components Unlike View Engine: • No NgZone •

    No default change detection • No application initialisers • No application initialisation status • No application bootstrap hook import { ɵrenderComponent as renderComponent } from '@angular/core'; import { AppComponent } from './app.component'; renderComponent(AppComponent); ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  22. We use Angular modules to • Configure injectors for runtime

    resolving of dependencies • Link declarables when compiling component templates • Bootstrap components as entry points to our applications • Lazy-load application features
  23. Lazy-loading tree-shakable components 1. Dynamically import the component file 2.

    Extract the component from the file 3. Bootstrap the component import { ɵrenderComponent as renderComponent } from '@angular/core'; import('./my-ivy.component').then(({ MyIvyComponent }) => renderComponent(MyIvyComponent); ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  24. This talk is possible thanks to ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS

    AND OPTIONAL NGMODULES Alexey Zuev Joost Koehoorn Max Koretskyi Morten Kirstein Wassim Chegham Zejiang Yu
  25. Tree-shakable components with Ivy • Get rid of all Angular

    modules • Bootstrap using renderComponent • Schedule change detection using markDirty when local UI state changes • Lazy-load application features using dynamic import and renderComponent ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES
  26. Techniques for getting started today ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND

    OPTIONAL NGMODULES View Engine Ivy preview with JIT Ivy preview with AOT SCAMs ✓ ✓ ✓ Component render modules ✓ Feature render modules ✓ ✓ Proposed component API
  27. Get in touch ANGULAR REVISITED: TREE-SHAKABLE COMPONENTS AND OPTIONAL NGMODULES

    bit.do/angular-revisited-slides bit.do/angular-revisited github.com/LayZeeDK/angular-revisited github.com/LayZeeDK twitter.com/LayZeeDK www.linkedin.com/in/larsgbn/ larsbrinknielsen@gmail.com