Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Angular Universal on Google App Engine
Search
Kenji Imamula
November 23, 2018
Technology
1.2k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Angular Universal on Google App Engine
東京Node学園祭2018での発表資料です。
Kenji Imamula
November 23, 2018
More Decks by Kenji Imamula
See All by Kenji Imamula
ビルドプロセスから考えるCSSアンチパターン
kimamula
3
1.7k
Other Decks in Technology
See All in Technology
Data + AI Summit 2026 イベントレポート: 「AIがビジネスで意思決定するデータ基盤」へ
nek0128
0
160
実装だけじゃない! CCA-F取得エンジニアが教えるClaude Code開発プロセス活用術
diggymo
2
740
SRE本の知られざる名シーン / The Hidden Gems of Google SRE Book
nari_ex
1
410
しぶいSRE: サーバから見えない障害にどう向き合うか。ラストワンマイルのデバッグ実践 / Shibui SRE
kanny
13
6.2k
Road to SRE NEXTの今までとこれから
hiroyaonoe
0
330
AI Coding Agent時代のcdk-nagガードレール 〜組織ルールを強制CIで守り抜く設計の挑戦〜
mhrtech
3
230
Devsumi 2026 Summer 人もAIも使える共通基盤を事業の加速装置にする~デザインシステム運用に学ぶ組織レバレッジ~ 渡辺 凌央
legalontechnologies
PRO
0
140
関数型の考えを TypeScript に持ち込んで、テストしやすい純粋関数を増やす / Pure at the Core, Effects at the Edge: Bringing Functional Thinking into TypeScript
kaminashi
1
120
インフラ寄りSREでも 開発に踏み出せる〜境界を越えてユーザー体験に向き合いたい〜
sansantech
PRO
2
3.9k
AIレビューはどこまで任せられるのか?自動化と人が背負うレビューの境界
sansantech
PRO
3
880
しくみを学んで使いこなそう GitHub Copilot app
torumakabe
2
250
脱金融のフューチャー・デザイン / Future Design Beyond Finance
ks91
PRO
0
150
Featured
See All Featured
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
610
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
800
The Art of Programming - Codeland 2020
erikaheidi
57
14k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
360
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
1
370
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
940
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
67
56k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
260
The SEO identity crisis: Don't let AI make you average
varn
0
510
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
410
Transcript
Angular Universal on Google App Engine ౦ژNodeֶԂࡇ2018 2018/11/23
גࣜձࣾΧϒΫ ࠓଜݠ࢜ @kimamula ˞("&߇͑Ί
About me •ࠓଜݠ࢜ •@kimamula •גࣜձࣾΧϒΫ •લ৬React->ݱ৬Angular •TypeScript ❤
Topics 1. What is Angular Universal 2. How to Angular
Universal 3. Hack Angular Universal
1. What is Angular Universal
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
Our use case SSRαʔόʔ ʢGAE SE/Node.jsʣ APIαʔόʔ ʢGAE SE/Pythonʣ Ӷҙ։ൃத
Google App EngineͱNode.js • 2018/06ɺSE (Standard Environment)Ͱ Node.jsΞϓϦͷσϓϩΠ͕Մೳʹ • ͨͩ͠ϕʔλ
• Node.js 8, 10ʹରԠ • majorόʔδϣϯΛࢦఆͯ͠σϓϩΠ • minor, patchόʔδϣϯউखʹ্͕Δ༷
2. How to Angular Universal
2-1. Getting Started
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
Slow Start https://angular.io/guide/universal • ެࣜυΩϡϝϯτ • આ໌ΛಡΈͳ͕ΒखॱΛͳͧΔ͜ͱͰɺ͋ ΔఔΈΛཧղͰ͖Δ • ऴ൫ͰQuick
Startʹॻ͍ͨखॱ͕ग़͖ͯͯ3 ΫοΩϯάײ͕͋Δ
Slow Start https://github.com/angular/universal-starter • ࠷খߏͷAngular UniversalΞϓϦ • angular.ioͷهࡌ༰ΑΓҰาઌΛߦͬͯ ͍ΔײʢϏϧυͷํ͕ҧͬͨΓ͢Δʣ •
Prerenderingʢޙड़ʣͷ࣮͋Γ
2-2. Angular Universal ։ൃͷجຊ
αʔόʔͱΫϥΠΞϯτͰίʔ υ͕ڞ௨ʹͳΔ͜ͱʹҙ͢Δ • αʔόʔ/ΫϥΠΞϯτͷͲͪΒ͔Ͱ͔͠ಈ͔ ͨ͘͠ͳ͍ॲཧΛదʹ੍ޚ͢Δ • αʔόʔͰ࣮ߦࡁΈͷॲཧ͕ΫϥΠΞϯτͰ ॏෳ࣮ͯ͠ߦ͞Εͳ͍Α͏ʹ͢Δ
αʔόʔͱΫϥΠΞϯτͰίʔ υ͕ڞ௨ʹͳΔ͜ͱʹҙ͢Δ • αʔόʔ/ΫϥΠΞϯτͷͲͪΒ͔Ͱ͔͠ಈ͔ ͨ͘͠ͳ͍ॲཧΛదʹ੍ޚ͢Δ • αʔόʔͰ࣮ߦࡁΈͷॲཧ͕ΫϥΠΞϯτͰ ॏෳ࣮ͯ͠ߦ͞Εͳ͍Α͏ʹ͢Δ
isPlatformBrowser, isPlatformServer • ॳظԽॲཧ྆ڥͰجຊతʹશ෦ಈ͘ • constructor, ngOnInit, … • ReactͷcomponentDidMountͷΑ͏ͳͷ
ͳ͍ • αʔόʔͷΈorΫϥΠΞϯτͷΈͰಈ͔ͨ͠ ͍ॲཧ͕͋Δ߹దٓఆ͕ඞཁ
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. } }
αʔόʔͱΫϥΠΞϯτͰίʔ υ͕ڞ௨ʹͳΔ͜ͱʹҙ͢Δ • αʔόʔ/ΫϥΠΞϯτͷͲͪΒ͔Ͱ͔͠ಈ͔ ͨ͘͠ͳ͍ॲཧΛదʹ੍ޚ͢Δ • αʔόʔͰ࣮ߦࡁΈͷॲཧ͕ΫϥΠΞϯτͰ ॏෳ࣮ͯ͠ߦ͞Εͳ͍Α͏ʹ͢Δ
Transferstate αʔόʔαΠυͰॳظԽͨ͠ঢ়ଶΛΫϥΠΞϯ ταΠυʹ͢Έ • HTML͚ͩͰΫϥΠΞϯτͰ࠶औಘ͕ඞཁ Server Page Request Browser ঢ়ଶͷॳظԽ
"1*ίʔϧ ֤छܭࢉॲཧ Rendered HTML including State ແବͳ"1*ίʔϧɺ ࠶ܭࢉΛ͙
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ʣ
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); } } ͞Εͨ ঢ়ଶͷऔಘ
2-3. ϋϚͬͨͱ͜Ζɺ ࠔͬͨͱ͜Ζ
styles.cssͷSSR https://github.com/angular/universal/issues/974
styles.cssͷSSR: • ίϯϙʔωϯτ͝ͱͷCSS • SSR͞ΕΔʢHTMLʹΠϯϥΠϯల։͞Ε Δʣ -> ॳظදࣔͷ࣌Ͱਖ਼͘͠ద༻͞ΕΔ •
styles.cssʢάϩʔόϧͳCSSʣ • SSR͞ΕͣɺJSͷॲཧͷதͰΠϯϥΠϯల։ ͞ΕΔ -> ద༻·Ͱʹϥά͕Ͱ͖Δ
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 { // ... }
watchϞʔυͰ։ൃ͍ͨ͠ https://github.com/angular/universal-starter/issues/490
DX with a CSR Angular app ng serveͰ؆୯ʹwatchϞʔυʹͳΔ 1.ίʔυฤू 2.ࣗಈϦϏϧυ
3.ϥΠϒϦϩʔυ
DX with a SSR Angular app ެࣜͷखॱʹهࡌͷscript͚ͩΛ͏߹ 1.ίʔυฤू 2.खಈͰϏϧυίϚϯυ࣮ߦ •
1͔ΒϏϧυͳͷͰΠϯΫϦϝϯλϧ͡Όͳ͍ 3.खಈͰNode.jsαʔόʔ࠶ىಈ 4.खಈͰϒϥβϦϩʔυ
ͭΒ͍
ࣗલͰͬͯΈΔ ”ng build --watchͨ͠ͷΛ͞Βʹhookͯ͠ExpressͳͲʹܨ͛ΔͱΑͦ͞͏”
Ϗϧυ͢Δͷ3ͭ 1. ΫϥΠΞϯτ͚AngularΞϓϦ 2. αʔόʔ͚AngularΞϓϦ 3. Express࣮ߦίʔυ • 2ͷϏϧυ࢈ʹґଘ ->
1, 2Angular CLIͷΈͰɺ 3webpackͷwatchϞʔυͰwatch͢Δ
ϏϧυͷྲྀΕ ίʔυฤू -> ΫϥΠΞϯτ͚AngularΞϓϦͷϏϧυ -> αʔόʔ͚AngularΞϓϦͷϏϧυ -> Express࣮ߦ༻ίʔυͷϏϧυ -> αʔόʔ࠶ىಈʢnodemonʣ
-> ϒϥβϦϩʔυʢbrowser-syncʣ
ࠓͷͱ͜Ζ͋·ΓշదͰͳ͍ ίʔυฤू -> ΫϥΠΞϯτ͚AngularΞϓϦͷϏϧυ -> αʔόʔ͚AngularΞϓϦͷϏϧυ -> Express࣮ߦ༻ίʔυͷϏϧυ -> αʔόʔ࠶ىಈʢnodemonʣ
-> ϒϥβϦϩʔυʢbrowser-syncʣ ͓͓ΉͶ~30ඵ HMRʹ͖͢ʁ
3. Hack Angular Universal
3-1. Prerender
Prerender or SSR https://github.com/angular/universal-starter#build-time-prerendering-vs-server-side-renderingssr Ϗϧυ࣌ʹੜͨ͠)5.-Λ ࣮ߦ࣌ʹ੩తʹ৴͢Δ
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) ); });
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.-Λ ϑΝΠϧʹग़ྗ
CSR vs SSR vs Prerender $43 443 1SFSFOEFS ΫϥΠΞϯτ ෛՙ
º ̋ ̋ αʔόʔ ෛՙ ̋ º ̋ ॊೈੑ ̋ ̋ º
CSR vs SSR vs Prerender $43 443 1SFSFOEFS ΫϥΠΞϯτ ෛՙ
º ̋ ̋ αʔόʔ ෛՙ ̋ º ̋ ॊೈੑ ̋ ̋ º ͜͜Λ̋ʹ Ͱ͖ͳ͍͔
ಈతίϯςϯπͷPrerender Server • ೝূ • ೝՄ • ݴޠ ͷఆ /some/path
PrerenderࡁΈHTML ঢ়گʹԠͯ͡దͳ HTMLΛฦ͢ ͜͏͍͏͜ͱ͕Ͱ͖ͨΒૉఢ͔…ʁ ʢݕ౼தʣ
3-2. HTTP/2 Server Push
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
Server Push with Angular CLI ະαϙʔτ https://github.com/angular/angular-cli/issues/11946
Server Push with Other FWs ͍ͬͯΔݶΓͰ • Polymer • Preact
• Nuxt.js
࡞ͬͯΈΔ 2௨Γͷ࡞Γํ • Preload link headersΛ͏ํ๏ -> ࠾༻ • ؆୯ʢৄࡉ࣍ͷεϥΠυͰʣ
• Node.jsͷAPI Λ͏ํ๏ • v10Ͱexperimentalϑϥάͳ͠Ͱ͑Δ Α͏ʹͳͬͨ • ExpressͰͷ͍উख͕ࠓͻͱͭ
Preload link headers 3FWFSTF QSPYZ #SPXTFS GET /index.html Index.html /css1.css
(push) /PEFKT GET /index.html Index.html Link: </css1.css>; rel=preload;
ͦͷύεͰඞཁͳϦιʔεʁ ҎԼͷํ๏Ͱఆ • Ϗϧυ࣌ͷwebpackͷstats͔ΒɺϞδϡʔ ϧͱchunkͷඥ͚ใΛಘΔ • SSRͷࡍ͜ͷใΛݩʹɺϩʔυ͞ΕͨϞ δϡʔϧ͕ଐ͢ΔchunkΛpreload link headersʹՃ͢Δ
ngx-server-push https://github.com/kimamula/ngx-server-push/ • ޭ • angular.ioͷखॱͰ࡞͍ͬͯΕɺߦखΛՃ ͑ΕಋೖͰ͖ΔΑ͏ʹ࡞ͬͨ • ͨͩ͠ɺࡉ͔͍ͱ͜Ζ͕৭ʑέΞͰ͖͍ͯͳ ͍ͷͰɺ࣮ઓೖͰ͖ΔϨϕϧͰͳ͍
·ͱΊ • Angular UniversalΛ࢝ΊΔʹ͋ͨͬͯಡΉ • https://angular.io/guide/universal • https://github.com/angular/universal- starter •
αʔόʔͱΫϥΠΞϯτͰίʔυ͕ڞ௨ʹͳ Δ͜ͱʹҙ͢Δ
·ͱΊ • αΫαΫwatchϞʔυͰ͖Δਓ͕͍ͨΒڭ͑ͯ ͍ͩ͘͞ • Prerenderݕ౼ͯ͠Έ·͠ΐ͏
Thank you!