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

Angular Universal on Google App Engine

Kenji Imamula
November 23, 2018

Angular Universal on Google App Engine

東京Node学園祭2018での発表資料です。

Kenji Imamula

November 23, 2018
Tweet

More Decks by Kenji Imamula

Other Decks in Technology

Transcript

  1. Angular Universal
    on Google App Engine


    ౦ژNodeֶԂࡇ2018
    2018/11/23
    גࣜձࣾΧϒΫ ࠓଜݠ࢜ @kimamula
    ˞("&੒෼߇͑Ί

    View Slide

  2. About me
    •ࠓଜݠ࢜
    •@kimamula
    •גࣜձࣾΧϒΫ
    •લ৬React->ݱ৬Angular
    •TypeScript ❤


    View Slide

  3. Topics
    1. What is Angular Universal
    2. How to Angular Universal
    3. Hack Angular Universal


    View Slide

  4. 1. What is Angular Universal


    View Slide

  5. Angular Universal
    https://github.com/angular/universal
    AngularΞϓϦέʔγϣϯͷSSRʢserver-side
    renderingʣΛՄೳʹ͢ΔͨΊͷϓϩδΣΫτ
    Server
    • Node.js
    • ASP.NET
    • (Python, Go, PHP)
    Page Request
    Browser
    "OHVMBS
    6OJWFSTBM
    Rendered HTML
    • SEO
    • Performance


    View Slide

  6. Our use case
    SSRαʔόʔ
    ʢGAE SE/Node.jsʣ
    APIαʔόʔ
    ʢGAE SE/Pythonʣ
    Ӷҙ։ൃத


    View Slide

  7. Google App EngineͱNode.js
    • 2018/06ɺSE (Standard Environment)Ͱ
    Node.jsΞϓϦͷσϓϩΠ͕Մೳʹ
    • ͨͩ͠ϕʔλ
    • Node.js 8, 10ʹରԠ
    • majorόʔδϣϯΛࢦఆͯ͠σϓϩΠ
    • minor, patchόʔδϣϯ͸উखʹ্͕Δ࢓༷


    View Slide

  8. 2. How to Angular Universal


    View Slide

  9. 2-1. Getting Started


    View Slide

  10. Quick Start
    Prerequisite: Angular CLI
    ؆୯ʂʂ
    $ ng new my-project
    $ cd my-project
    $ ng add @nguniversal/express-engine --clientProject my-project
    $ npm run build:ssr && npm run serve:ssr
    # …
    Node Express server listening on http://localhost:4000


    View Slide

  11. Slow Start
    https://angular.io/guide/universal
    • ެࣜυΩϡϝϯτ
    • આ໌ΛಡΈͳ͕ΒखॱΛͳͧΔ͜ͱͰɺ͋
    Δఔ౓࢓૊ΈΛཧղͰ͖Δ
    • ऴ൫ͰQuick Startʹॻ͍ͨखॱ͕ग़͖ͯͯ3
    ෼ΫοΩϯάײ͕͋Δ


    View Slide

  12. Slow Start
    https://github.com/angular/universal-starter
    • ࠷খߏ੒ͷAngular UniversalΞϓϦ
    • angular.ioͷهࡌ಺༰ΑΓ΋ҰาઌΛߦͬͯ
    ͍ΔײʢϏϧυͷ࢓ํ͕ҧͬͨΓ͢Δʣ
    • Prerenderingʢޙड़ʣͷ࣮૷͋Γ


    View Slide

  13. 2-2. Angular Universal
    ։ൃͷجຊ


    View Slide

  14. αʔόʔͱΫϥΠΞϯτͰίʔ
    υ͕ڞ௨ʹͳΔ͜ͱʹ஫ҙ͢Δ
    • αʔόʔ/ΫϥΠΞϯτͷͲͪΒ͔Ͱ͔͠ಈ͔
    ͨ͘͠ͳ͍ॲཧΛద੾ʹ੍ޚ͢Δ
    • αʔόʔͰ࣮ߦࡁΈͷॲཧ͕ΫϥΠΞϯτͰ
    ॏෳ࣮ͯ͠ߦ͞Εͳ͍Α͏ʹ͢Δ


    View Slide

  15. αʔόʔͱΫϥΠΞϯτͰίʔ
    υ͕ڞ௨ʹͳΔ͜ͱʹ஫ҙ͢Δ
    • αʔόʔ/ΫϥΠΞϯτͷͲͪΒ͔Ͱ͔͠ಈ͔
    ͨ͘͠ͳ͍ॲཧΛద੾ʹ੍ޚ͢Δ
    • αʔόʔͰ࣮ߦࡁΈͷॲཧ͕ΫϥΠΞϯτͰ
    ॏෳ࣮ͯ͠ߦ͞Εͳ͍Α͏ʹ͢Δ


    View Slide

  16. isPlatformBrowser,
    isPlatformServer
    • ॳظԽॲཧ͸྆؀ڥͰجຊతʹશ෦ಈ͘
    • constructor, ngOnInit, …
    • ReactͷcomponentDidMountͷΑ͏ͳ΋ͷ
    ͸ͳ͍
    • αʔόʔͷΈorΫϥΠΞϯτͷΈͰಈ͔ͨ͠
    ͍ॲཧ͕͋Δ৔߹͸దٓ൑ఆ͕ඞཁ


    View Slide

  17. isPlatformBrowser,
    isPlatformServer
    import { PLATFORM_ID } from '@angular/core';
    import {
    isPlatformBrowser,
    isPlatformServer
    } from '@angular/common';
    constructor(
    @Inject(PLATFORM_ID) private platformId: Object
    ) {}
    ngOnInit() {
    if (isPlatformBrowser(this.platformId)) {
    // Client only code.
    }
    if (isPlatformServer(this.platformId)) {
    // Server only code.
    }
    }


    View Slide

  18. αʔόʔͱΫϥΠΞϯτͰίʔ
    υ͕ڞ௨ʹͳΔ͜ͱʹ஫ҙ͢Δ
    • αʔόʔ/ΫϥΠΞϯτͷͲͪΒ͔Ͱ͔͠ಈ͔
    ͨ͘͠ͳ͍ॲཧΛద੾ʹ੍ޚ͢Δ
    • αʔόʔͰ࣮ߦࡁΈͷॲཧ͕ΫϥΠΞϯτͰ
    ॏෳ࣮ͯ͠ߦ͞Εͳ͍Α͏ʹ͢Δ


    View Slide

  19. Transferstate
    αʔόʔαΠυͰॳظԽͨ͠ঢ়ଶΛΫϥΠΞϯ
    ταΠυʹ౉͢࢓૊Έ
    • HTML͚ͩͰ͸ΫϥΠΞϯτͰ࠶औಘ͕ඞཁ
    Server
    Page Request
    Browser
    ঢ়ଶͷॳظԽ
    "1*ίʔϧ
    ֤छܭࢉॲཧ
    Rendered HTML
    including State
    ແବͳ"1*ίʔϧɺ
    ࠶ܭࢉΛ๷͙


    View Slide

  20. Transferstate: αʔόʔ
    import { TransferState } from '@angular/platform-browser';
    import { TRANSFER_STATE_KEY } from './transfer-state-key';
    constructor(transferState: TransferState) {
    // …
    transferState.onSerialize(TRANSFER_STATE_KEY, () => {
    return state;
    });
    }
    import { makeStateKey } from '@angular/platform-browser';
    export const TRANSFER_STATE_KEY = makeStateKey('MY_KEY');
    ঢ়ଶڞ༗ͷͨΊ
    ͷΩʔͷ࡞੒
    ԿΒ͔ͷํ๏ͰΞϓϦέʔγϣϯͷ
    ঢ়ଶΛऔಘͯ͠ฦ͢ʢFH/H3Yʣ


    View Slide

  21. Transferstate: ΫϥΠΞϯτ
    import { TransferState } from '@angular/platform-browser';
    import { TRANSFER_STATE_KEY } from './transfer-state-key';
    constructor(transferState: TransferState) {
    if (transferState.hasKey(TRANSFER_STATE_KEY)) {
    const state = transferState.get(
    TRANSFER_STATE_KEY,
    defaultValue
    );
    this.transferState.remove(TRANSFER_STATE_KEY);
    }
    }
    ౉͞Εͨ
    ঢ়ଶͷऔಘ


    View Slide

  22. 2-3. ϋϚͬͨͱ͜Ζɺ
    ࠔͬͨͱ͜Ζ


    View Slide

  23. styles.cssͷSSR
    https://github.com/angular/universal/issues/974


    View Slide

  24. styles.cssͷSSR: ໰୊
    • ίϯϙʔωϯτ͝ͱͷCSS
    • SSR͞ΕΔʢHTMLʹΠϯϥΠϯల։͞Ε
    Δʣ -> ॳظදࣔͷ࣌఺Ͱਖ਼͘͠ద༻͞ΕΔ
    • styles.cssʢάϩʔόϧͳCSSʣ
    • SSR͞ΕͣɺJSͷॲཧͷதͰΠϯϥΠϯల։
    ͞ΕΔ -> ద༻·Ͱʹϥά͕Ͱ͖Δ


    View Slide

  25. styles.cssͷSSR: workaround
    • ԼͷΑ͏ͳSCSSͷΈͷίϯϙʔωϯτΛ࡞Γ
    • AppServerModuleͷbootstrapͰࢦఆ͢Δ
    ৄࡉ: https://github.com/Angular-RU/angular-universal-starter/commit/dbb413b
    // inline-style.component.scss
    @import 'path/to/styles.scss';
    @NgModule({
    // ...
    bootstrap: [AppComponent, InlineStyleComponent]
    })
    export class AppServerModule {
    // ...
    }


    View Slide

  26. watchϞʔυͰ։ൃ͍ͨ͠
    https://github.com/angular/universal-starter/issues/490


    View Slide

  27. DX with a CSR Angular app
    ng serveͰ؆୯ʹwatchϞʔυʹͳΔ
    1.ίʔυฤू
    2.ࣗಈϦϏϧυ
    3.ϥΠϒϦϩʔυ


    View Slide

  28. DX with a SSR Angular app
    ެࣜͷखॱʹهࡌͷscript͚ͩΛ࢖͏৔߹
    1.ίʔυฤू
    2.खಈͰϏϧυίϚϯυ࣮ߦ
    • 1͔ΒϏϧυͳͷͰΠϯΫϦϝϯλϧ͡Όͳ͍
    3.खಈͰNode.jsαʔόʔ࠶ىಈ
    4.खಈͰϒϥ΢βϦϩʔυ


    View Slide

  29. ͭΒ͍


    View Slide

  30. ࣗલͰ΍ͬͯΈΔ
    ”ng build --watchͨ͠΋ͷΛ͞Βʹhookͯ͠ExpressͳͲʹܨ͛ΔͱΑͦ͞͏”


    View Slide

  31. Ϗϧυ͢Δ΋ͷ͸3ͭ
    1. ΫϥΠΞϯτ޲͚AngularΞϓϦ
    2. αʔόʔ޲͚AngularΞϓϦ
    3. Express࣮ߦίʔυ
    • 2ͷϏϧυ࢈෺ʹґଘ
    -> 1, 2͸Angular CLIͷ࢓૊ΈͰɺ
    3͸webpackͷwatchϞʔυͰwatch͢Δ


    View Slide

  32. ϏϧυͷྲྀΕ
    ίʔυฤू
    -> ΫϥΠΞϯτ޲͚AngularΞϓϦͷϏϧυ
    -> αʔόʔ޲͚AngularΞϓϦͷϏϧυ
    -> Express࣮ߦ༻ίʔυͷϏϧυ
    -> αʔόʔ࠶ىಈʢnodemonʣ
    -> ϒϥ΢βϦϩʔυʢbrowser-syncʣ


    View Slide

  33. ࠓͷͱ͜Ζ͋·ΓշదͰ͸ͳ͍
    ίʔυฤू
    -> ΫϥΠΞϯτ޲͚AngularΞϓϦͷϏϧυ
    -> αʔόʔ޲͚AngularΞϓϦͷϏϧυ
    -> Express࣮ߦ༻ίʔυͷϏϧυ
    -> αʔόʔ࠶ىಈʢnodemonʣ
    -> ϒϥ΢βϦϩʔυʢbrowser-syncʣ
    ͓͓ΉͶ~30ඵ HMRʹ͢΂͖ʁ


    View Slide

  34. 3. Hack Angular Universal


    View Slide

  35. 3-1. Prerender


    View Slide

  36. Prerender or SSR
    https://github.com/angular/universal-starter#build-time-prerendering-vs-server-side-renderingssr


    Ϗϧυ࣌ʹੜ੒ͨ͠)5.-Λ
    ࣮ߦ࣌ʹ੩తʹ഑৴͢Δ

    View Slide

  37. How to prerender
    universal-starterϦϙδτϦͷprerender.tsΑΓൈਮʢҰ෦վมʣ
    ['/', '/lazy', '/lazy/nested'].forEach(route => {
    const fullPath = join(BROWSER_FOLDER, route);
    previousRender = previousRender
    .then(_ =>
    renderModuleFactory(AppServerModuleNgFactory, {
    document: index,
    url: route,
    extraProviders: [
    provideModuleMap(LAZY_MODULE_MAP)
    ]
    })
    ).then(html =>
    writeFileSync(join(fullPath, 'index.html'), html)
    );
    });


    View Slide

  38. How to prerender
    universal-starterϦϙδτϦͷprerender.tsΑΓൈਮʢҰ෦վมʣ


    ['/', '/lazy', '/lazy/nested'].forEach(route => {
    const fullPath = join(BROWSER_FOLDER, route);
    previousRender = previousRender
    .then(_ =>
    renderModuleFactory(AppServerModuleNgFactory, {
    document: index,
    url: route,
    extraProviders: [
    provideModuleMap(LAZY_MODULE_MAP)
    ]
    })
    ).then(html =>
    writeFileSync(join(fullPath, 'index.html'), html)
    );
    });
    QSFSFOEFS
    ͢ΔύεͷҰཡ
    ύεʹର͢Δ
    )5.-Λੜ੒
    ੜ੒͞Εͨ)5.-Λ
    ϑΝΠϧʹग़ྗ

    View Slide

  39. CSR vs SSR vs Prerender
    $43 443 1SFSFOEFS
    ΫϥΠΞϯτ
    ෛՙ
    º ̋ ̋
    αʔόʔ
    ෛՙ
    ̋ º ̋
    ॊೈੑ ̋ ̋ º


    View Slide

  40. CSR vs SSR vs Prerender
    $43 443 1SFSFOEFS
    ΫϥΠΞϯτ
    ෛՙ
    º ̋ ̋
    αʔόʔ
    ෛՙ
    ̋ º ̋
    ॊೈੑ ̋ ̋ º
    ͜͜Λ̋ʹ
    Ͱ͖ͳ͍͔


    View Slide

  41. ಈతίϯςϯπͷPrerender
    Server
    • ೝূ
    • ೝՄ
    • ݴޠ
    ౳ͷ൑ఆ
    /some/path
    PrerenderࡁΈHTML
    ঢ়گʹԠͯ͡ద੾ͳ
    HTMLΛฦ͢
    ͜͏͍͏͜ͱ͕Ͱ͖ͨΒૉఢ͔΋…ʁ
    ʢݕ౼தʣ


    View Slide

  42. 3-2. HTTP/2 Server Push


    View Slide

  43. HTTP/2 Server Push
    4FSWFS
    #SPXTFS
    GET /css1.css
    Without Push
    4FSWFS
    #SPXTFS
    GET /index.html
    Index.html
    With Push
    /css1.css (push)
    GET /index.html
    Index.html
    /css1.css


    View Slide

  44. Server Push with Angular CLI
    ະαϙʔτ
    https://github.com/angular/angular-cli/issues/11946


    View Slide

  45. Server Push with Other FWs
    ஌͍ͬͯΔݶΓͰ͸
    • Polymer
    • Preact
    • Nuxt.js


    View Slide

  46. ࡞ͬͯΈΔ
    2௨Γͷ࡞Γํ
    • Preload link headersΛ࢖͏ํ๏ -> ࠾༻
    • ؆୯ʢৄࡉ͸࣍ͷεϥΠυͰʣ
    • Node.jsͷAPI Λ࢖͏ํ๏
    • v10Ͱexperimentalϑϥάͳ͠Ͱ࢖͑Δ
    Α͏ʹͳͬͨ
    • ExpressͰͷ࢖͍উख͕ࠓͻͱͭ


    View Slide

  47. Preload link headers
    3FWFSTF
    QSPYZ
    #SPXTFS
    GET /index.html
    Index.html
    /css1.css (push)
    /PEFKT
    GET /index.html
    Index.html
    Link: ;
    rel=preload;


    View Slide

  48. ͦͷύεͰඞཁͳϦιʔε͸ʁ
    ҎԼͷํ๏Ͱ൑ఆ
    • Ϗϧυ࣌ͷwebpackͷstats͔ΒɺϞδϡʔ
    ϧͱchunkͷඥ෇͚৘ใΛಘΔ
    • SSRͷࡍ͜ͷ৘ใΛݩʹɺϩʔυ͞ΕͨϞ
    δϡʔϧ͕ଐ͢ΔchunkΛpreload link
    headersʹ௥Ճ͢Δ


    View Slide

  49. ngx-server-push
    https://github.com/kimamula/ngx-server-push/
    • ੒ޭ
    • angular.ioͷखॱͰ࡞͍ͬͯΕ͹ɺ਺ߦखΛՃ
    ͑Ε͹ಋೖͰ͖ΔΑ͏ʹ࡞ͬͨ
    • ͨͩ͠ɺࡉ͔͍ͱ͜Ζ͕৭ʑέΞͰ͖͍ͯͳ
    ͍ͷͰɺ࣮ઓ౤ೖͰ͖ΔϨϕϧͰ͸ͳ͍


    View Slide

  50. ·ͱΊ
    • Angular UniversalΛ࢝ΊΔʹ͋ͨͬͯಡΉ
    • https://angular.io/guide/universal
    • https://github.com/angular/universal-
    starter
    • αʔόʔͱΫϥΠΞϯτͰίʔυ͕ڞ௨ʹͳ
    Δ͜ͱʹ஫ҙ͢Δ


    View Slide

  51. ·ͱΊ
    • αΫαΫwatchϞʔυͰ͖Δਓ͕͍ͨΒڭ͑ͯ
    ͍ͩ͘͞
    • Prerender΋ݕ౼ͯ͠Έ·͠ΐ͏


    View Slide

  52. Thank you!


    View Slide