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.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
多摩川(.dev)ランニング入門 / Tamagawa.dev#3
fujiwara3
3
360
こんなアーキテクチャ図は嫌だ BEYOND THE TIME: 半年後の自分へ贈る15のメッセージ / 15 of Anti-pattern in AWS Architecture Diagrams
naospon
3
240
grill-me(grilling):AI駆動開発を超助けてくれるSkill / grill me
mathbullet
0
110
どんな手を使っても絶対間に合わせるスケジューラ
asari194617
0
1.6k
AIで仕事のやり方を変える
matsu7874
1
560
Sony-DroidKaigi2026
sony
1
320
はじめてのDatabricks:技術者向けワークショップ / beginner-workshop
databricksjapan
PRO
0
150
AI-DLCって実際どう? 〜聞きたいこと全部聞いてみる〜
news_it_enj
0
220
【Oracle AI Spotlight ウェビナー】AWSか、Azureか、Google Cloudか。その議論にオラクルを含める意義。
oracle4engineer
PRO
2
230
Redmine 7.0で私が開発した新機能の狙いと背景
vividtone
1
110
Kiro Crewしか勝たん!?
miu_crescent
PRO
0
180
Bet AI Day 2026丨AIを「使う」から、AIが「働く」へ ― LayerXが進める「組織AI」の社会実装
layerx
PRO
3
2.2k
Featured
See All Featured
Automating Front-end Workflow
addyosmani
1369
210k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
320
Code Review Best Practice
trishagee
74
20k
Rails Girls Zürich Keynote
gr2m
96
14k
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
2
410
Evolving SEO for Evolving Search Engines
ryanjones
0
280
BBQ
matthewcrist
89
10k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
520
Being A Developer After 40
akosma
91
590k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
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!