Angular Toolset Support

82bafb0432ce4ccc9dcc26f94d5fe5bc?s=47 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!

82bafb0432ce4ccc9dcc26f94d5fe5bc?s=128

Minko Gechev

October 22, 2016
Tweet

Transcript

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

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

  3. None
  4. Hold on for the second edition!

  5. agenda

  6. None
  7. What’s Angular?

  8. None
  9. None
  10. None
  11. None
  12. None
  13. Here Here Here

  14. None
  15. None
  16. None
  17. None
  18. None
  19. None
  20. None
  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
  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
  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
  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
  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
  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
  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
  28. Where to start? https://flic.kr/p/pcf4cU

  29. angular-cli

  30. ng new hello-world

  31. angular-cli • Quick bootstrap of projects • Scaffolding of: •

    Components • Services • … • Uses Webpack • Support for mobile toolkit, material, etc.
  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
  33. angular-seed

  34. None
  35. None
  36. None
  37. @ludohenin @TheDonDope @d3viant0ne @Shyam-Chen @NathanWalker

  38. git clone git@github.com/mgechev/angular-seed

  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
  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
  41. Other starters • angular2-webpack-starter • Webpack based • angular2-seed-advanced •

    NativeScript, Electron, etc. • Based on angular-seed
  42. Development process and experience https://flic.kr/p/daxeMY

  43. Typical JavaScript experience

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

    in mind
  45. None
  46. We already have • Superset of JavaScript • Compile time

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

  48. Angular 1 <user name="literal"></user> <user name="expression"></user>

  49. <user name="hero.name + ' Avengers'"></user> <user name="hero.name + ' Avengers'"></user>

    Angular 1
  50. <!-- name="hero.name + ' Avengers'" --> <user name="hero.name + '

    Avengers'"></user> <!-- name="Captain America Avengers" --> <user name="hero.name + ' Avengers'"></user> Angular 1
  51. <!-- name="Captain America Avengers" --> <user name="hero.name + ' Avengers'"></user>

    <!-- name="hero.name + ' Avengers'" --> <user name="hero.name + ' Avengers'"></user> Angular 1
  52. <user name="literal"></user> <user [name]="expression"></user> Angular 2

  53. <!-- name="hero.name + ' Avengers'" --> <user name="hero.name + '

    Avengers'"></user> <!-- name="Captain America Avengers" --> <user [name]="hero.name + ' Avengers'"></user> Angular 2
  54. Angular 2 Component @Component({ selector: 'hero-details', template: ` <h1 [innerText]="hero.name

    + ' Avengers'"></h1> <section> Age: <span>{{ formatAge(hero.age) }}</span> </section> ` }) class HeroDetailsComponent { hero: Superhero; formatAge(age: number) { // ... } }
  55. Does property exist @Component({ selector: 'hero-details', template: ` <h1 [innerText]="hero.name

    + ' Avengers'"></h1> <section> Age: <span>{{ formatAge(hero.age) }}</span> </section> ` }) class HeroDetailsComponent { hero: Superhero; formatAge(age: number) { // ... } }
  56. Type checking @Component({ selector: 'hero-details', template: ` <h1 [innerText]="hero.name +

    ' Avengers'"></h1> <section> Age: <span>{{ formatAge(hero.age) }}</span> </section> ` }) class HeroDetailsComponent { hero: Superhero; formatAge(age: number) { // ... } }
  57. Advanced type checking @Component({ selector: 'hero-details', template: ` <h1 [innerText]="hero.name

    + ' Avengers'"></h1> <section> Age: <span>{{ formatAge(hero.age) }}</span> </section> ` }) class HeroDetailsComponent { hero: Superhero; formatAge(age: number) { // ... } }
  58. github.com/mgechev/ codelyzer

  59. “Codelyzer contains set of rules that provide automated alignment to

    the Angular Style Guide & improvement of our development experience”
  60. None
  61. None
  62. Why not instant feedback*

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

  65. None
  66. Language Service • Syntax highlighting in templates • Syntax and

    semantic error reporting • Auto-completion in templates
  67. AoT compilation

  68. How Angular works?

  69. Disclaimer The description is simplified and does not completely align

    with the actual implementation.
  70. component.ts import { Component } from '@angular/core'; @Component({ selector: 'my-app',

    template: `<header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header>` }) export class Component { name: string; }
  71. interface InternalComponent { create(); detectChanges(); destroy(); } internal-component.ts For more

    information: http://bit.ly/2dsk6z5
  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
  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 <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header>
  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 <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header>
  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 <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header>
  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 <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header>
  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
  78. const template = `<header> <h1>Hello {{ name }}!</h1> <p> Summary

    of the awesome app! </p> </header>`; header h1 p TextNode TextNode Interp Expr Template to AST
  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!')); <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header>
  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!')); <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header>
  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!')); <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header>
  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!')); <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header> header h1 p TextNode TextNode Interp Expr create()
  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!')); <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header> header h1 p TextNode TextNode Interp Expr create()
  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!')); <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header> header h1 p TextNode TextNode Interp Expr create()
  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!')); <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header> header h1 p TextNode TextNode Interp Expr create()
  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!')); <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header> header h1 p TextNode TextNode Interp Expr create()
  87. detectChanges() class InternalComponent { //... detectChanges() { let val =

    interpolate('Hello', this.context.name, '!'); if (this.binding !== val) { r.createText(this.h1, val); this.binding = val; } } //... }
  88. You can bind ONLY to public members

  89. What about encapsulation

  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'; }
  91. --stripInternal import { Component } from 'library'; const cmp =

    new Component(); // Property 'name' does not exist on type 'Component'. cmp.name = 'Captain America';
  92. Why do we need to generate detectChanges?

  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
  94. CD with codegen • Easier to reason about • Obviously

    fast • Inline caching performance boost • VM friendly code
  95. None
  96. If the codegen happens at build time, it’s called AoT;

    if it happens at runtime, it’s called JiT
  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
  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 <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header>
  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); //... } ... <header> <h1>Hello {{ name }}!</h1> <p> Summary of the awesome app! </p> </header> vs
  100. AoT generated code has explicit imports so the bundler knows

    what the app uses
  101. Introducing ngc

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

  103. ngc is a wrapper over tsc

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

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

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

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

  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
  109. ngc compatible third-party libraries must be distributed with *.metadata.json

  110. AoT compiled application has a slightly different bootstrap mechanism

  111. JiT bootstrap import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import {

    AppModule } from './app.module'; platformBrowserDynamic().bootstrapModule(AppModule);
  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);
  113. None
  114. Resources • Angular CLI • AoT in Angular 2 •

    Building an Angular 2 Application for Production • 2.5X Smaller Angular 2 Apps with GCC • Codelyzer
  115. mgv.io/ngtool-feedback

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