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
壊して学ぶAWS CDK: そのcdk deployで消えるもの、残るもの
k_adachi_01
1
480
VPCセキュリティ対応の最新事情
nagisa53
1
290
大量データに対しても、生成AIを用いてリーズナブルにデータ加工をしたい!Databricksのai_queryについて調べてみた
kamoshika
2
280
OpenTelemetryにおけるGoのゼロコード・コンパイル時計装について #fukuokago
quiver
0
230
[Droidcon Orlando '26] The Android Lens: Applying Mobile Forensics to AI Performance
amanda_hinchman
1
110
Multicaで30個のミニプロジェクトをAIエージェント運用して見えてきたこと
eiei114
1
630
ここは地獄!つらい朝会を体験することで、チームとしてのより良い振る舞いに気づくワークショップ / The stand-up meeting from hell in the game industry
scrummasudar
0
230
Power Automateアップデート情報
miyakemito
0
100
AI時代のYAGNI:「爆速で無駄になった機能」からの学び / 20260720 Naoki Takahashi
shift_evolve
PRO
3
540
GoでCコンパイラを作った話
repunit
0
150
AI、CDK と協働する Full TypeScript アプリケーション開発 / Full TypeScript Application with AI and CDK
geekplus_tech
2
480
AI時代こそ、スケールしないことをしよう -「作る人」から「なぜ作るか」を考える人へ / Do Things That Don't Scale in the AI Era — From How to Why
kaminashi
1
110
Featured
See All Featured
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
260
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.6k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
5
1.1k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
740
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.1k
Building AI with AI
inesmontani
PRO
1
1.1k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.7k
First, design no harm
axbom
PRO
2
1.2k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
660
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
2.1k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
750
The SEO identity crisis: Don't let AI make you average
varn
0
520
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!