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

Angular Toolset Support

Minko Gechev
October 22, 2016

Angular Toolset Support

The tooling support of the modern web frameworks advances constantly. It helps us with managing boilerplates, having more efficient and automated build process. It even helps us be more consistent and confident during our development cycle, with techniques such as static code analysis! Angular is designed with tooling in mind from the beginning! Static typing, ES2015 modules and many decisions on architectural level allow development of sophisticated tools. Such tools help us be more productive during our development process. In this talk we're going to make an overview of the toolset support for Angular. We'll briefly describe Angular CLI, Codelyzer and many other projects that can be an essential part of our development workflow!

Minko Gechev

October 22, 2016
Tweet

More Decks by Minko Gechev

Other Decks in Programming

Transcript

  1. ngular
    Minko Gechev
    github.com/mgechev
    twitter.com/mgechev
    blog.mgechev.com
    toolset support (extended)
    https://flic.kr/p/fipdcK

    View Slide

  2. github.com/mgechev
    twitter.com/mgechev
    blog.mgechev.com
    About
    deprecated

    View Slide

  3. View Slide

  4. Hold on for the
    second edition!

    View Slide

  5. agenda

    View Slide

  6. View Slide

  7. What’s Angular?

    View Slide

  8. View Slide

  9. View Slide

  10. View Slide

  11. View Slide

  12. View Slide

  13. Here
    Here
    Here

    View Slide

  14. View Slide

  15. View Slide

  16. View Slide

  17. View Slide

  18. View Slide

  19. View Slide

  20. View Slide

  21. Angular Tooling
    • Angular’s AoT compiler
    • TypeScript compiler
    • Testing
    • Unit testing
    • e2e testing
    • Coverage
    • Module loader
    • Bundler
    • Provides bundling and tree shaking
    • Linter
    • TypeScript and CSS
    • Minifier
    • Minification & deadcode elimination
    • Service workers

    View Slide

  22. • Angular’s AoT compiler
    • TypeScript compiler
    • Testing
    • Unit testing
    • e2e testing
    • Coverage
    • Module loader
    • Bundler
    • Provides bundling and tree shaking
    • Linter
    • TypeScript and CSS
    • Minifier
    • Minification & deadcode elimination
    • Service workers
    Angular Tooling

    View Slide

  23. • Angular’s AoT compiler
    • TypeScript compiler
    • Testing
    • Unit testing
    • e2e testing
    • Coverage
    • Module loader
    • Bundler
    • Provides bundling and tree shaking
    • Linter
    • TypeScript and CSS
    • Minifier
    • Minification & deadcode elimination
    • Service workers
    Angular Tooling

    View Slide

  24. • Angular’s AoT compiler
    • TypeScript compiler
    • Testing
    • Unit testing
    • e2e testing
    • Coverage
    • Module loader
    • Bundler
    • Provides bundling and tree shaking
    • Linter
    • TypeScript and CSS
    • Minifier
    • Minification & deadcode elimination
    • Service workers
    Angular Tooling

    View Slide

  25. • Angular’s AoT compiler
    • TypeScript compiler
    • Testing
    • Unit testing
    • e2e testing
    • Coverage
    • Module loader
    • Bundler
    • Provides bundling and tree shaking
    • Linter
    • TypeScript and CSS
    • Minifier
    • Minification & deadcode elimination
    • Service workers
    Angular Tooling

    View Slide

  26. • Angular’s AoT compiler
    • TypeScript compiler
    • Testing
    • Unit testing
    • e2e testing
    • Coverage
    • Module loader
    • Bundler
    • Provides bundling and tree shaking
    • Linter
    • TypeScript and CSS
    • Minifier
    • Minification & deadcode elimination
    • Service workers
    Angular Tooling

    View Slide

  27. • Angular’s AoT compiler
    • TypeScript compiler
    • Testing
    • Unit testing
    • e2e testing
    • Coverage
    • Module loader
    • Bundler
    • Provides bundling and tree shaking
    • Linter
    • TypeScript and CSS
    • Minifier
    • Minification & deadcode elimination
    • Service workers management/generation
    Angular Tooling

    View Slide

  28. Where to start?
    https://flic.kr/p/pcf4cU

    View Slide

  29. angular-cli

    View Slide

  30. ng new hello-world

    View Slide

  31. angular-cli
    • Quick bootstrap of projects
    • Scaffolding of:
    • Components
    • Services
    • …
    • Uses Webpack
    • Support for mobile toolkit, material, etc.

    View Slide

  32. # serves the application
    ng serve
    # generate new component
    ng g component my-new-component
    # build an app with env config
    ng build --prod --env=prod
    ng build --dev --env=dev
    CLI 101

    View Slide

  33. angular-seed

    View Slide

  34. View Slide

  35. View Slide

  36. View Slide

  37. @ludohenin @TheDonDope
    @d3viant0ne
    @Shyam-Chen @NathanWalker

    View Slide

  38. git clone [email protected]/mgechev/angular-seed

    View Slide

  39. angular-seed
    • Modular statically typed build
    • Multiple apps in the same project
    • Well maintained & easy to update
    • AoT compilation support
    • Unit & e2e testing
    • Test coverage
    • tslint and codelyzer

    View Slide

  40. # build & start the dev server
    npm start
    # test the app
    npm t
    # build with env config
    npm run build.prod --env-config custom
    # build with AoT
    npm run build.prod.exp
    Seed 101

    View Slide

  41. Other starters
    • angular2-webpack-starter
    • Webpack based
    • angular2-seed-advanced
    • NativeScript, Electron, etc.
    • Based on angular-seed

    View Slide

  42. Development process and experience
    https://flic.kr/p/daxeMY

    View Slide

  43. Typical JavaScript experience

    View Slide

  44. Angular is…
    • Built with TypeScript
    • Designed with tooling in mind

    View Slide

  45. View Slide

  46. We already have
    • Superset of JavaScript
    • Compile time type checking

    View Slide

  47. Analyzable templates
    https://flic.kr/p/irHwLW

    View Slide

  48. Angular 1


    View Slide



  49. Angular 1

    View Slide





  50. Angular 1

    View Slide





  51. Angular 1

    View Slide



  52. Angular 2

    View Slide





  53. Angular 2

    View Slide

  54. Angular 2 Component
    @Component({
    selector: 'hero-details',
    template: `


    Age: {{ formatAge(hero.age) }}

    `
    })
    class HeroDetailsComponent {
    hero: Superhero;
    formatAge(age: number) {
    // ...
    }
    }

    View Slide

  55. Does property exist
    @Component({
    selector: 'hero-details',
    template: `


    Age: {{ formatAge(hero.age) }}

    `
    })
    class HeroDetailsComponent {
    hero: Superhero;
    formatAge(age: number) {
    // ...
    }
    }

    View Slide

  56. Type checking
    @Component({
    selector: 'hero-details',
    template: `


    Age: {{ formatAge(hero.age) }}

    `
    })
    class HeroDetailsComponent {
    hero: Superhero;
    formatAge(age: number) {
    // ...
    }
    }

    View Slide

  57. Advanced type checking
    @Component({
    selector: 'hero-details',
    template: `


    Age: {{ formatAge(hero.age) }}

    `
    })
    class HeroDetailsComponent {
    hero: Superhero;
    formatAge(age: number) {
    // ...
    }
    }

    View Slide

  58. github.com/mgechev/
    codelyzer

    View Slide

  59. “Codelyzer contains set of rules that provide
    automated alignment to the Angular Style Guide
    & improvement of our development experience”

    View Slide

  60. View Slide

  61. View Slide

  62. Why not
    instant feedback*

    View Slide

  63. View Slide

  64. Trusted by
    • Angular team
    • jQWidgets
    • ng2-bootstrap

    View Slide

  65. View Slide

  66. Language Service
    • Syntax highlighting in templates
    • Syntax and semantic error reporting
    • Auto-completion in templates

    View Slide

  67. AoT
    compilation

    View Slide

  68. How Angular works?

    View Slide

  69. Disclaimer
    The description is simplified and does not completely
    align with the actual implementation.

    View Slide

  70. component.ts
    import { Component } from '@angular/core';
    @Component({
    selector: 'my-app',
    template: `
    Hello {{ name }}!

    Summary of the awesome app!

    `
    })
    export class Component {
    name: string;
    }

    View Slide

  71. interface InternalComponent {
    create();
    detectChanges();
    destroy();
    }
    internal-component.ts
    For more information: http://bit.ly/2dsk6z5

    View Slide

  72. class InternalComponent {
    create() {
    this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));
    }
    //...
    }
    create method

    View Slide

  73. class InternalComponent {
    create() {
    this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));
    }
    //...
    }
    create method

    Hello {{ name }}!

    Summary of the awesome app!


    View Slide

  74. class InternalComponent {
    create() {
    this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));
    }
    //...
    }
    create method

    Hello {{ name }}!

    Summary of the awesome app!


    View Slide

  75. class InternalComponent {
    create() {
    this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));
    }
    //...
    }
    create method

    Hello {{ name }}!

    Summary of the awesome app!


    View Slide

  76. class InternalComponent {
    create() {
    this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));
    }
    //...
    }
    create method

    Hello {{ name }}!

    Summary of the awesome app!


    View Slide

  77. class InternalComponent {
    create() {
    this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));
    }
    //...
    }
    create method

    View Slide

  78. const template = `
    Hello {{ name }}!

    Summary of the awesome app!

    `;
    header
    h1 p
    TextNode
    TextNode
    Interp
    Expr
    Template to AST

    View Slide

  79. header
    h1 p
    TextNode
    TextNode
    Interp
    Expr
    create()
    this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));

    Hello {{ name }}!

    Summary of the awesome app!


    View Slide

  80. header
    h1 p
    TextNode
    TextNode
    Interp
    Expr
    create()
    this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));

    Hello {{ name }}!

    Summary of the awesome app!


    View Slide

  81. header
    h1 p
    TextNode
    TextNode
    Interp
    Expr
    create()
    this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));

    Hello {{ name }}!

    Summary of the awesome app!


    View Slide

  82. this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));

    Hello {{ name }}!

    Summary of the awesome app!


    header
    h1 p
    TextNode
    TextNode
    Interp
    Expr
    create()

    View Slide

  83. this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));

    Hello {{ name }}!

    Summary of the awesome app!


    header
    h1 p
    TextNode
    TextNode
    Interp
    Expr
    create()

    View Slide

  84. this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));

    Hello {{ name }}!

    Summary of the awesome app!


    header
    h1 p
    TextNode
    TextNode
    Interp
    Expr
    create()

    View Slide

  85. this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));

    Hello {{ name }}!

    Summary of the awesome app!


    header
    h1 p
    TextNode
    TextNode
    Interp
    Expr
    create()

    View Slide

  86. this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    this.p =
    r.createElement(this.header, 'p');
    r.createText(this.p,
    'Summary of the awesome app!'));

    Hello {{ name }}!

    Summary of the awesome app!


    header
    h1 p
    TextNode
    TextNode
    Interp
    Expr
    create()

    View Slide

  87. detectChanges()
    class InternalComponent {
    //...
    detectChanges() {
    let val = interpolate('Hello',
    this.context.name, '!');
    if (this.binding !== val) {
    r.createText(this.h1, val);
    this.binding = val;
    }
    }
    //...
    }

    View Slide

  88. You can bind
    ONLY to public
    members

    View Slide

  89. What about
    encapsulation

    View Slide

  90. encapsulation
    tsc demo.component.ts --stripInternal
    TypeScript will omit
    name from the d.ts files
    @Component({
    selector: 'my-app',
    template: `...`
    })
    export class Component {
    /** @internal */
    name: string = 'Iron Man';
    }

    View Slide

  91. --stripInternal
    import { Component } from 'library';
    const cmp = new Component();
    // Property 'name' does not exist on type 'Component'.
    cmp.name = 'Captain America';

    View Slide

  92. Why do we need to generate
    detectChanges?

    View Slide

  93. Scope.prototype.$digest = function () {
    'use strict';
    var dirty, watcher, current, i;
    do {
    dirty = false;
    for (i = 0; i < this.$$watchers.length; i += 1) {
    watcher = this.$$watchers[i];
    current = this.$eval(watcher.exp);
    if (!Utils.equals(watcher.last, current)) {
    watcher.last = Utils.clone(current);
    dirty = true;
    watcher.fn(current);
    }
    }
    } while (dirty);
    for (i = 0; i < this.$$children.length; i += 1) {
    this.$$children[i].$digest();
    }
    };
    Traditional CD
    http://bit.ly/2dS0d7P

    View Slide

  94. CD with codegen
    • Easier to reason about
    • Obviously fast
    • Inline caching performance boost
    • VM friendly code

    View Slide

  95. View Slide

  96. If the codegen happens at build
    time, it’s called AoT; if it happens
    at runtime, it’s called JiT

    View Slide

  97. AoT Brings
    • Easy drop of unused components in bundle
    • Code which is easy for dead-code elimination
    • Fast initial rendering
    • Components are distributed pre-compiled
    • Allows us to drop compiler from bundler
    • We compile ahead of time so we don’t need it runtime

    View Slide

  98. import { interpolate, Renderer, ... } from "…";
    ...
    create() {
    this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    //...
    }
    ...
    vs

    Hello {{ name }}!

    Summary of the awesome app!


    View Slide

  99. import { interpolate, Renderer, ... } from "…";
    ...
    create() {
    this.header =
    r.createElement('header');
    this.h1 =
    r.createElement(this.header, 'h1');
    this.binding = interpolate('Hello',
    this.context.name, '!');
    r.createText(this.h1, this.binding);
    //...
    }
    ...

    Hello {{ name }}!

    Summary of the awesome app!


    vs

    View Slide

  100. AoT generated code has explicit imports
    so the bundler knows what the app uses

    View Slide

  101. Introducing ngc

    View Slide

  102. ./node_modules/.bin/ngc -p tsconfig.json

    View Slide

  103. ngc is a wrapper over tsc

    View Slide

  104. ngc will produce
    • *.ngfactory.ts
    • *.css.shim.ts
    • *.metadata.json

    View Slide

  105. *.ngfactory.ts contains the
    “internal components” we described

    View Slide

  106. *.css.shim.ts contains the scoped
    component styles

    View Slide

  107. *.metadata.json contains component
    metadata (i.e., Angular specific
    decorators)

    View Slide

  108. {
    "decorators": [{
    "expression": {
    "__symbolic": "reference",
    "module": "@angular/core",
    "name": "Component"
    },
    "arguments": [{
    "selector": "sd-app",
    "templateUrl": "app.html"
    }]
    }]
    }
    @Component({
    selector: 'sd-app',
    templateUrl: 'app.html',
    })
    export class AppComponent {}
    app.ts *app.metadata.json

    View Slide

  109. ngc compatible
    third-party libraries must be distributed
    with *.metadata.json

    View Slide

  110. AoT
    compiled application has a slightly
    different bootstrap mechanism

    View Slide

  111. JiT bootstrap
    import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
    import { AppModule } from './app.module';
    platformBrowserDynamic().bootstrapModule(AppModule);

    View Slide

  112. import { platformBrowser } from '@angular/platform-browser';
    import { AppModuleNgFactory } from './app.module.ngfactory';
    platformBrowser().bootstrapModule(AppModule);
    JiT bootstrap
    AoT bootstrap
    import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
    import { AppModule } from './app.module';
    platformBrowserDynamic().bootstrapModule(AppModule);

    View Slide

  113. View Slide

  114. Resources
    • Angular CLI
    • AoT in Angular 2
    • Building an Angular 2 Application for Production
    • 2.5X Smaller Angular 2 Apps with GCC
    • Codelyzer

    View Slide

  115. mgv.io/ngtool-feedback

    View Slide

  116. Thank you!
    github.com/mgechev
    twitter.com/mgechev
    blog.mgechev.com

    View Slide