Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Angular Universal on Google App Engine
Search
Kenji Imamula
November 23, 2018
Technology
1.3k
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
顧客の成果創出とプロダクトの成長を 両立するためのFDE
sansantech
PRO
0
530
Claude Designがめちゃくちゃ便利なので使ってほしい
diggymo
0
170
「大丈夫そう?」をObservabilityで確かめる
mrmtsu
0
240
Terraformを用いたJamf Pro構成のIaC, GitOps化への挑戦
yukun
0
120
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
16
120k
10年欲しかった音楽管理アプリを、AIと一緒に作りはじめた
judau
1
190
Kiro Meetup #8 Kiro アップデート (2026/3/21〜2026/9/24)
katzueno
1
310
AI臭い文章とは何なのか
nasuvitz
36
75k
音声コミュニティを守るAI監視基盤_ 90%以上の入力削減を支えたServerless設計と運用判断
shuheioka123
0
120
AIに書かせて、プラットフォームで縛る ― EKSプラットフォームで実践した責任境界と権限設計
elmodev09
1
1.1k
AI駆動開発で仕様はどこまで書くべきか? ― 人とAIの責務境界から考える開発プロセスの実践
takahiromatsui
1
250
カンファレンスに参加した後の浮遊感とセルフケア
pauli
0
260
Featured
See All Featured
The Cult of Friendly URLs
andyhume
79
7k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.3k
4 Signs Your Business is Dying
shpigford
187
23k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.4k
Color Theory Basics | Prateek | Gurzu
gurzu
1
480
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.7k
Skip the Path - Find Your Career Trail
mkilby
1
240
It's Worth the Effort
3n
188
29k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
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!