Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

1. What is Angular Universal  

Slide 5

Slide 5 text

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  

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

2. How to Angular Universal  

Slide 9

Slide 9 text

2-1. Getting Started  

Slide 10

Slide 10 text

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  

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

2-2. Angular Universal ։ൃͷجຊ  

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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. } }  

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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ʣ  

Slide 21

Slide 21 text

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); } } ౉͞Εͨ ঢ়ଶͷऔಘ  

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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 { // ... }  

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

ͭΒ͍  

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

3. Hack Angular Universal  

Slide 35

Slide 35 text

3-1. Prerender  

Slide 36

Slide 36 text

Prerender or SSR https://github.com/angular/universal-starter#build-time-prerendering-vs-server-side-renderingssr   Ϗϧυ࣌ʹੜ੒ͨ͠)5.-Λ ࣮ߦ࣌ʹ੩తʹ഑৴͢Δ

Slide 37

Slide 37 text

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) ); });  

Slide 38

Slide 38 text

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.-Λ ϑΝΠϧʹग़ྗ

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

3-2. HTTP/2 Server Push  

Slide 43

Slide 43 text

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  

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

Thank you!