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

Building Fast Angular Applications By Default

Building Fast Angular Applications By Default

Angular grew significantly in the past few years from both a tooling and developer experience standpoint. This talk will explore many of the features and newer improvements in the pipeline that allow anyone to build and deploy performant apps with very little overhead. Through real demos and examples, we’ll cover Ivy, bundle budgeting, differential serving, automatic code-splitting, and progressive rehydration of SSR elements. In the second part of the talk, we’ll focus on how to efficiently prefetch and preload different modules and components.

Minko Gechev

April 06, 2019
Tweet

More Decks by Minko Gechev

Other Decks in Programming

Transcript

  1. @mgechev
    Building Fast Angular Applications by Default
    Minko Gechev
    twitter.com/mgechev

    github.com/mgechev

    blog.mgechev.com

    View Slide

  2. @yourtwitter
    Description or Image
    @twitterhandle
    Agenda
    ● Network performance
    ● Runtime performance
    ● Good practices
    ● Application in production
    ● Initial rendering

    View Slide

  3. @yourtwitter
    Network performance Description or Image
    @twitterhandle

    View Slide

  4. @yourtwitter
    @mgechev
    Good practices
    ● Ship fewer bytes of JavaScript
    ● Lazy loading
    ● Preloading & prefetching
    ● Server-side rendering
    ● Write efficient code

    View Slide

  5. @yourtwitter
    Shipping less JavaScript

    View Slide

  6. @yourtwitter
    @mgechev
    ● Minification/dead code elimination
    ● Differential loading or serving
    ● Code-splitting
    Shipping fewer bytes

    View Slide

  7. @yourtwitter
    @mgechev
    ● Minification/dead code elimination
    ● Differential loading or serving
    ● Code-splitting
    Shipping fewer bytes

    View Slide

  8. @yourtwitter
    @mgechev
    Differential loading
    ● Produce ES5 bundles for newer browsers
    ● Do not send polyfills to modern browsers
    ● Smaller payload
    ● Do not downlevel modern features
    ● Faster execution
    ● Smaller payload

    View Slide

  9. @mgechev
    -40KB polyfills
    -7% each bundle

    View Slide

  10. @mgechev
    Step 1: Load HTML Step 2: Look at script tags Step 2: Download right
    version
    Differential loading

    View Slide

  11. @mgechev
    Step 1: Load HTML Step 2: Request JS
    Differential serving
    Step 3: Return JS based on
    userAgent

    View Slide

  12. @yourtwitter
    @mgechev
    Differential loading
    ✅ Simple deployment infrastructure
    ✅ Proposal for a browser standard
    WHATWG

    View Slide

  13. @yourtwitter
    Differential loading



    Differential loading






    View Slide

  14. @yourtwitter
    Differential loading



    Differential loading






    View Slide

  15. @mgechev

    View Slide

  16. @yourtwitter
    Angular CLI
    Introduced this feature in
    v8.0.0

    View Slide

  17. @yourtwitter
    @mgechev
    ● Set the target in tsconfig.json
    to es2015
    ● Set the minimum supported browsers
    in browserlist
    Differential loading with Angular CLI version 8

    View Slide

  18. @yourtwitter
    @mgechev
    ● Minification/dead code elimination
    ● Differential loading or serving
    ● Code-splitting
    Shipping fewer bytes

    View Slide

  19. twitter.com/mgechev
    lazy-loading

    View Slide

  20. @yourtwitter
    @mgechev
    ● Component-level
    ● Route-level
    Code-splitting could be

    View Slide

  21. @yourtwitter
    @mgechev
    ● Component-level
    ● Route-level
    Code-splitting could be

    View Slide

  22. @mgechev

    View Slide

  23. @mgechev

    View Slide

  24. @mgechev
    https://www.youtube.com/watch?v=MMPl9wHzmS4

    View Slide

  25. @yourtwitter
    @mgechev
    ● Component-level
    ● Route-level
    Code-splitting could be

    View Slide

  26. @mgechev

    View Slide

  27. @yourtwitter
    Route-based code-splitting
    const routes: Routes = [
    {
    path: 'settings',
    loadChildren: './settings/settings.module#SettingsModule'
    },
    {
    path: 'article',
    loadChildren: './article/article.module#ArticleModule'
    }
    ];

    View Slide

  28. @yourtwitter
    Route-based code-splitting in Ivy
    const routes: Routes = [
    {
    path: 'settings',
    loadChildren: import('./settings/settings.module')
    .then(m => m.SettingsModule);
    },

    ...
    ];

    View Slide

  29. @yourtwitter
    Route-based code-splitting in Ivy
    const routes: Routes = [
    {
    path: 'settings',
    loadChildren: import('./settings/settings.module')
    .then(m => m.SettingsModule);
    },

    ...
    ];
    Experimental

    View Slide

  30. @yourtwitter
    @mgechev
    1. Definition of a lazy module
    2. Declaration of a lazy route
    3. Definition of a component
    4. Declaration of a eager route
    Steps for creating a lazy-loaded module

    View Slide

  31. @mgechev

    View Slide

  32. @yourtwitter
    Route-based code-splitting with the future Angular CLI
    $ ng g module about --route=about --module=index

    View Slide

  33. @yourtwitter
    @mgechev
    Questions

    View Slide

  34. @mgechev

    View Slide

  35. @mgechev

    View Slide

  36. twitter.com/mgechev
    Step 1: Open
    https://example.com/
    Step 2: Determine JavaScript
    which is likely to be required
    Step 3: Download the
    chunks
    Step 4: Store chunks
    in browser cache
    Pre-fetching

    View Slide

  37. twitter.com/mgechev

    View Slide

  38. @yourtwitter
    @mgechev
    ● Prefetch visible links
    ● Predictive prefetching
    ● Prefetch on mouse over
    Prefetching strategies

    View Slide

  39. @yourtwitter
    @mgechev
    ● Prefetch visible links
    ● Predictive prefetching
    ● Prefetch on mouse over
    Prefetching strategies

    View Slide

  40. @mgechev

    View Slide

  41. @yourtwitter
    Prefetch visible links
    $ npm install ngx-quicklink

    View Slide

  42. @yourtwitter
    Prefetch visible links
    import { QuicklinkStrategy } from 'ngx-quicklink';
    @NgModule({
    imports: [RouterModule.forRoot(routes, {
    preloadingStrategy: QuicklinkStrategy
    })],
    exports: [RouterModule]
    })
    export class AppRoutingModule {}

    View Slide

  43. @yourtwitter
    Prefetch visible links
    import { QuicklinkModule } from 'ngx-quicklink';
    @NgModule({
    imports: [
    ...
    QuicklinkModule
    ],
    exports: [
    ...
    QuicklinkModule,
    ]
    })
    export class SharedModule {}

    View Slide

  44. @yourtwitter
    @mgechev
    ● Prefetch visible links
    ● Predictive prefetching
    ● Prefetch on mouse over
    Prefetching strategies

    View Slide

  45. @mgechev

    View Slide

  46. @mgechev

    View Slide

  47. @mgechev
    early
    alpha

    View Slide

  48. @mgechev
    A performance budget is
    a limit for pages which
    the team is not allowed to
    exceed.
    Addy Osmani

    View Slide

  49. @yourtwitter
    Performance Budgets
    enforces constraints to let
    you have guarantees
    v8.0.0
    https://angular.io/guide/build

    View Slide

  50. @yourtwitter
    Angular projects
    without compression
    >27%

    View Slide

  51. @yourtwitter
    >80%
    Angular projects
    without CDN

    View Slide

  52. @yourtwitter
    ng deploy
    $ ng add [PROVIDER]
    $ ng run app:deploy

    View Slide

  53. @mgechev

    View Slide

  54. @mgechev
    Partnering with

    View Slide

  55. @yourtwitter
    @mgechev
    Questions

    View Slide

  56. @yourtwitter
    Server-side rendering

    View Slide

  57. @mgechev
    Step 1: Request page Step 2: Render page Step 3: Paint & load JS
    Server-side rendering
    Step 4: Bootstrap app

    View Slide

  58. @yourtwitter
    @mgechev
    ● Faster initial contentful paint
    ● Better SEO
    ● Better time to interactive?
    Benefits of SSR

    View Slide

  59. @mgechev
    Step 1: Request page Step 2: Render page Step 3: Paint & load JS
    Server-side rendering
    Step 4: Bootstrap app

    View Slide

  60. @mgechev
    Step 1: Request page Step 2: Render page Step 3: Paint & load JS
    Server-side rendering
    Step 4: Bootstrap app

    View Slide

  61. @mgechev
    https://addyosmani.com/blog/rehydration/

    View Slide

  62. twitter.com/mgechev
    Destructive Rehydration
    DOM Component tree

    View Slide

  63. twitter.com/mgechev
    Progressive Rehydration
    DOM
    ( )

    View Slide

  64. twitter.com/mgechev
    Progressive Rehydration
    DOM
    ( )

    View Slide

  65. twitter.com/mgechev
    ( )
    Progressive Rehydration
    DOM

    View Slide

  66. twitter.com/mgechev
    ( )
    Progressive Rehydration
    DOM

    View Slide

  67. twitter.com/mgechev
    ( )
    Progressive Rehydration
    DOM
    ChildCmp1

    View Slide

  68. twitter.com/mgechev
    ( )
    Progressive Rehydration
    DOM
    ChildCmp1

    View Slide

  69. twitter.com/mgechev
    ( )
    Progressive Rehydration
    DOM
    ChildCmp1

    View Slide

  70. twitter.com/mgechev
    ( )
    Progressive Rehydration
    DOM
    ChildCmp1
    ChildCmp2

    View Slide

  71. twitter.com/mgechev
    ( )
    Progressive Rehydration
    DOM
    ChildCmp1
    ChildCmp2

    View Slide

  72. twitter.com/mgechev
    ( )
    Progressive Rehydration
    DOM
    RootCmp
    ChildCmp1
    ChildCmp2

    View Slide

  73. @yourtwitter
    Progressive bootstrapping

    View Slide

  74. @mgechev
    Step 1: Request page Step 2: Render page Step 3: Paint & load JS
    Server-side rendering
    Step 4: Bootstrap app

    View Slide

  75. @mgechev
    Step 1: Request page Step 2: Render page Step 3: Paint & load JS
    Server-side rendering
    Step 4: Bootstrap app

    View Slide

  76. @mgechev
    Step 1: Request page Step 2: Render page Step 3: Paint & load JS
    Server-side rendering
    Step 4: Bootstrap app

    View Slide

  77. twitter.com/mgechev
    Progressive loading
    DOM

    View Slide

  78. twitter.com/mgechev
    Progressive loading
    DOM

    Key down

    View Slide

  79. twitter.com/mgechev
    Progressive loading
    DOM
    ChildCmp

    View Slide

  80. @yourtwitter
    Faster Rendering

    View Slide

  81. @yourtwitter
    @mgechev
    ● Discovery of dependencies
    ● Efficient code generation
    ● Efficient runtime
    Runtime optimizations

    View Slide

  82. @mgechev
    Model View dependencies
    Compiler




    Front-end Back-end
    Input Output

    View Slide

  83. @mgechev

    {{ comment.body + 'foo' }}

    if (rf & 1) {
    // Create
    } if (rf & 2) {
    ɵtextBinding(3,
    ɵinterpolation1(" ",
    ctx.comment.body, " " ...));
    }

    View Slide

  84. @yourtwitter
    @mgechev
    ● Tree-shakeable code
    ● Monomorphic executions
    Efficient code generation

    View Slide

  85. @mgechev
    Tree-shakeable code
    import { ɵelementStart, … } from ...
    if (rf & 1) {
    ɵelementStart(0, "div", _c0);
    ɵelementStart(2, "p", _c2);
    ɵtext(3);
    ɵelementEnd();
    ɵelementEnd();
    } if (rf & 2) {
    ɵtextBinding(3, ...
    ɵinterpolation1( ...)
    }
    The compiler imports only
    what given component needs

    View Slide

  86. @yourtwitter
    @mgechev
    In collaboration with v8 team to
    make sure we generate code
    optimizable by the JavaScript engine
    Monomorphic code

    View Slide

  87. @yourtwitter
    @mgechev
    Summary
    ● Reducing the bundle size
    ● Speeding up user navigations
    ● Automated deployment via CLI
    ● Progressive rehydration
    ● Compile-time optimizations

    View Slide

  88. @yourtwitter
    @mgechev
    Questions

    View Slide

  89. @mgechev
    Thank you!
    twitter.com/mgechev

    github.com/mgechev

    blog.mgechev.com

    View Slide