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
日経電子版へのPWA導入事例
Search
Ryo yasuda
October 31, 2018
Programming
1
350
日経電子版へのPWA導入事例
Ryo yasuda
October 31, 2018
Tweet
Share
More Decks by Ryo yasuda
See All by Ryo yasuda
GKE+Istio+GitOpsで作る日経電子版の次世代マイクロサービス基盤
ryysd
3
2.1k
Microservices on Fastly v1.1
ryysd
2
1.1k
Microservices on Fastly
ryysd
42
22k
Other Decks in Programming
See All in Programming
生成AIコーディングとの向き合い方、AIと共創するという考え方 / How to deal with generative AI coding and the concept of co-creating with AI
seike460
PRO
1
320
Datadog RUM 本番導入までの道
shinter61
1
310
技術懸念に立ち向かい 法改正を穏便に乗り切った話
pop_cashew
0
1.5k
XSLTで作るBrainfuck処理系
makki_d
0
210
Webからモバイルへ Vue.js × Capacitor 活用事例
naokihaba
0
730
Go Modules: From Basics to Beyond / Go Modulesの基本とその先へ
kuro_kurorrr
0
120
ドメインモデリングにおける抽象の役割、tagless-finalによるDSL構築、そして型安全な最適化
knih
11
1.9k
カクヨムAndroidアプリのリブート
numeroanddev
0
430
セキュリティマネジャー廃止とクラウドネイティブ型サンドボックス活用
kazumura
1
190
C++20 射影変換
faithandbrave
0
500
Create a website using Spatial Web
akkeylab
0
290
FormFlow - Build Stunning Multistep Forms
yceruto
1
190
Featured
See All Featured
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
657
60k
Designing Experiences People Love
moore
142
24k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
2.8k
Rails Girls Zürich Keynote
gr2m
94
14k
We Have a Design System, Now What?
morganepeng
52
7.6k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
32
5.9k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
46
9.6k
Into the Great Unknown - MozCon
thekraken
39
1.9k
The Language of Interfaces
destraynor
158
25k
Transcript
ܦిࢠ൛ͷPWAಋೖࣄྫ ຊܦࡁ৽ฉࣾ ҆ా ཽ "84%FW%BZ
ࣗݾհ ҆ా ཽ (ͩ͢ Γΐ͏) 2015: NTTݚڀॴ ೖࣾ - ίϯςφܕԾԽٕज़ؔ࿈ͷݚڀʹैࣄ
2016: ຊܦࡁ৽ฉࣾ ೖࣾ - ܦిࢠ൛ϦχϡʔΞϧ൛ ։ൃϝϯόʔ - ϑϩϯτΤϯυɾόοΫΤϯυɾΠϯϑϥॾʑ୲ Α͘ॻ͘ݴޠ: js, golang, python
ܦిࢠ൛ 20103݄ץ ຖ900ຊͷهࣄΛ৴ ༗ྉձһ54ສਓҎ্ɾແྉձһ300ສਓҎ্ ݄ؒ3ԯΞΫηε
ܦిࢠ൛ ϦχϡʔΞϧ ϓϩδΣΫτ (r.nikkei) SPAഇࢭ UI/UXվળ (PWAԽɾϨεϙϯγϒԽ) MicroservicesΞʔΩςΫνϟͷ࠾༻
ϦχϡʔΞϧʹΑΔޮՌ Before After
ϦχϡʔΞϧʹΑΔޮՌ •58% better conversion rate •40% more daily active user
•2x faster Speed Index •14 seconds faster Time-To-Interactive •2.3x organic traffic
PWA(Progressive Web Application)ͱ ωΠςΟϒΞϓϦΆ͍UXΛఏڙ͢ΔWebΞϓϦ
PWAͱ – GoogleʹΑΔఆٛ • Fast • ϖʔδͷϩʔυɾԠ͕͍ • Reliable •
ωοτϫʔΫঢ়گʹґଘ͠ͳ͍(ΦϑϥΠϯͰར༻Մೳ) • Engaging • ϓογϡ௨ • ϗʔϜը໘ͷՃ https://developers.google.com/web/progressive-web-apps/checklist
ܦʹ͓͚ΔPWA • Fast • ϦχϡʔΞϧલͷഒͷදࣔ • Reliable • τοϓͷهࣄͳͲΦϑϥΠϯͰӾཡՄ •
Engaging • ϓογϡ௨ • ϗʔϜը໘ͷՃ
Fast
ϑΝʔετϏϡʔදࣔͷ࠷దԽ • ϑΝʔετϏϡʔ • WebϖʔδΛ։͍ͨ࣌࠷ॳʹݟ͑ΔྖҬ • ͜ͷྖҬͷදࣔʹؔΘΔॲཧΛ࠷༏ઌ
ϑΝʔετϏϡʔදࣔͷ࠷దԽ – PRPLύλʔϯ • Push: ϑΝʔετϏϡʔͷඳըʹඞཁͳϦιʔεΛPush • Render: ϑΝʔετϏϡʔΛඳը •
Pre-cache: ࣍ʹඞཁͳϦιʔεϖʔδΛPre-cache • Lazyload: ϑΝʔετϏϡʔ֎ͷίϯςϯπΛLazyload *Googleͷఏএ͢ΔSPAΛલఏͱͨ͠PRPLύλʔϯͱҟͳΔͷͷࢀߟʹ͍ͯ͠Δ
ϑΝʔετϏϡʔදࣔͷ࠷దԽ – PRPLύλʔϯ • Push: ϑΝʔετϏϡʔͷඳըʹඞཁͳϦιʔεΛPush • Render: ϑΝʔετϏϡʔΛඳը •
Pre-cache: ࣍ʹඞཁͳϦιʔεϖʔδΛPre-cache • Lazyload: ϑΝʔετϏϡʔ֎ͷίϯςϯπΛLazyload *Googleͷఏএ͢ΔSPAΛલఏͱͨ͠PRPLύλʔϯͱҟͳΔͷͷࢀߟʹ͍ͯ͠Δ
HTTP/2 Server Push ΫϥΠΞϯτ͔ΒͷϦΫΤετແ͠ʹαʔό͔Βσʔλૹ৴ ΫϥΠΞϯτ αʔό ΫϥΠΞϯτ αʔό index.html bundle.js
bundle.css index.html index.html bundle.js bundle.css Pushແ͠ Push༗Γ
HTTP/2 Server Push Pushແ͠ Push༗Γ ϖʔδͷμϯϩʔυޙʹjsɾcssΛμϯϩʔυ ϖʔδͷμϯϩʔυͱฒߦͯ͠jsɾcssΛμϯϩʔυ
• HTTP/2 Server H2OΛར༻ • Link HeaderʹϦιʔεΛهड़͢ΔͱPushͯ͘͠ΕΔ HTTP/2 Server Push
Origin Server H2O Client Link:<bundle.js>;rel=preload;, <bundle.css>; rel=preload; Push: bundle.css Push: bundle.js
• Fastly(CDN)͕LinkϔομΛͬͨPushΛαϙʔτ • r.nikkeiͰFastlyͬͯͨͷͰPushͷಋೖͷखؒখ͍͞ HTTP/2 Server Push Origin Server Fastly
(CDN) Client Link:<bundle.js>;rel=preload;, <bundle. css>; rel=preload; Push: bundle.css Push: bundle.js
ϑΝʔετϏϡʔදࣔͷ࠷దԽ – PRPLύλʔϯ • Push: ϑΝʔετϏϡʔͷඳըʹඞཁͳϦιʔεΛPush • Render: ϑΝʔετϏϡʔΛඳը •
Pre-cache: ࣍ʹඞཁͳϦιʔεϖʔδΛPre-cache • Lazyload: ϑΝʔετϏϡʔ֎ͷίϯςϯπΛLazyload *Googleͷఏএ͢ΔSPAΛલఏͱͨ͠PRPLύλʔϯͱҟͳΔͷͷࢀߟʹ͍ͯ͠Δ
Render – Critical Rendering Pathͷ࠷దԽ Request Page Start building DOM
Build CSSOM Run JS Continue Building DOM Render Page GET html Response Response Response GET css GET js
Render – Critical Rendering Pathͷ࠷దԽ Request Page GET html
Render – Critical Rendering Pathͷ࠷దԽ Request Page Start building DOM
GET html Response
Render – Critical Rendering Pathͷ࠷దԽ Request Page Start building DOM
GET html Response GET css GET js
Render – Critical Rendering Pathͷ࠷దԽ Request Page Start building DOM
Build CSSOM Run JS GET html Response Response Response GET css GET js
Render – Critical Rendering Pathͷ࠷దԽ Request Page Start building DOM
Build CSSOM Run JS Continue Building DOM GET html Response Response Response GET css GET js
Render – Critical Rendering Pathͷ࠷దԽ Request Page Start building DOM
Build CSSOM Run JS Continue Building DOM Render Page GET html Response Response Response GET css GET js
Render – Critical Rendering Pathͷ࠷దԽ Request Page Start building DOM
Build CSSOM Run JS Continue Building DOM Render Page GET html Response Response Response GET css GET js CSSϒϩοΩϯά JSϒϩοΩϯά
Render – Critical CSS • ϑΝʔετϏϡʔʹඞཁͳCSSͷΈΛinlineͰຒΊࠐΉ ɾ ɾ ɾ ←ͷදࣔʹඞཁͳ࠷ݶͷCSSΛ
HTMLʹຒΊࠐΉ ←ͷCSSը໘දࣔޙʹಡΈࠐΉ
Render – Critical CSS • ϑΝʔετϏϡʔʹඞཁͳCSSͷΈΛinlineͰຒΊࠐΉ • CSSऔಘʹඞཁͳϦΫΤετΛݮΒͤΔ • CSSOMߏஙɾϨΠΞτͷ࣌ؒΛݮͰ͖Δ
Render – Critical CSS • ҎલπʔϧͰࣗಈੜ͍ͯͨ͠ (https://github.com/addyosmani/critical) • ඞཁͳCSS༷ʑͳ݅ͰมΘΔͷͰࣗಈੜͰ͍͠ •
ݱࡏਓखͰඞཁͳCSSΛཧ هࣄ༰ʹΑͬͯϑΝʔετϏϡʔʹೖΔཁૉ͕ඍົʹมΘΔ
Render – async/defer <script src= ”/bundle.js” async> <script src=”/bundle.js” defer>
• r.nikkeinon-SPA+SSRͳͷͰϑΝʔετϏϡʔදࣔʹjsෆཁ • jsͷ࣮ߦը໘දࣔޙͰे • async/deferͰjsͷಡΈࠐΈɾ࣮ߦλΠϛϯάΛมߋ
Render – async/defer ύʔα͕scriptλάʹ౸ୡ HTMLύʔεྃ DOMContentLoaded default https://html.spec.whatwg.org/multipage/scripting.html#attr-script-async HTMLύʔε JSμϯϩʔυ
JS࣮ߦ
Render – async/defer ύʔα͕scriptλάʹ౸ୡ HTMLύʔεྃ DOMContentLoaded default async https://html.spec.whatwg.org/multipage/scripting.html#attr-script-async HTMLύʔε
JSμϯϩʔυ JS࣮ߦ
Render – async/defer ύʔα͕scriptλάʹ౸ୡ HTMLύʔεྃ DOMContentLoaded default async defer https://html.spec.whatwg.org/multipage/scripting.html#attr-script-async
HTMLύʔε JSμϯϩʔυ JS࣮ߦ jsͷDLɾ࣮ߦʹΑΔ ϒϩοΩϯάΛճආ
Render – Critical Rendering Pathͷ࠷దԽ Request Page Start building DOM
Build CSSOM Run JS Continue Building DOM Render Page GET html Response Response Response GET css GET js
Render – Critical Rendering Pathͷ࠷దԽ Request Page Build CSSOM Run
JS Continue Building DOM Render Page GET Html + Critical CSS Response Response GET js Start building DOM
ϑΝʔετϏϡʔදࣔͷ࠷దԽ – PRPLύλʔϯ • Push: ϑΝʔετϏϡʔͷඳըʹඞཁͳϦιʔεΛPush • Render: ϑΝʔετϏϡʔΛඳը •
Pre-cache: ࣍ʹඞཁͳϦιʔεϖʔδΛPre-cache • Lazyload: ϑΝʔετϏϡʔ֎ͷίϯςϯπΛLazyload *Googleͷఏএ͢ΔSPAΛલఏͱͨ͠PRPLύλʔϯͱҟͳΔͷͷࢀߟʹ͍ͯ͠Δ
Pre-cache Ϣʔβ͕࣍ʹඞཁͱ͢ΔίϯςϯπΛࣄલʹΩϟογϡ
Pre-cache – ServiceWorker • ϒϥβ্ʹଘࡏ͢ΔϓϩΩγαʔόΈ͍ͨͳͷ • jsͰॊೈʹΩϟογϡͷ੍ޚ͕Մೳ • ΦϑϥΠϯͰΩϟογϡʹΞΫηεՄೳ ϒϥβ
Service Worker Cache Network
Pre-cache – ServiceWorkerͷޮՌͷҰྫ ServiceWorkerແ͠ ServiceWorker༗Γ
Pre-cache – Ωϟογϡઓུ • τοϓϖʔδே༦ץͷهࣄͳͲΛΩϟογϡ • ճ༡͠ͳ͍Ϣʔβʹpre-cache͠ͳ͍ • େ͖ͳίϯςϯπwifiଓ࣌ͷΈΩϟογϡ NetworkInformation
APIͰwifiଓঢ়گ֬ೝ
Pre-cache Service Workerॊೈ͚ͩͲख͔͔ؒΔ
Pre-cache – ΩϟογϡͷTTLཧ • ݹ͍ΩϟογϡΛআͯ͘͠ΕͨΓ͠ͳ͍ͷͰࣗલ࣮ • URLͱtimestampΛIndexed DBʹอଘ • Ωϟογϡߋ৽࣌ʹtimestampൺֱͯ͠ݹ͚Εআ
Pre-cache – Ωϟογϡͷಉظ • Ϣʔβͷೝূঢ়ଶ͕มԽͨ͠ࡍʹෆ߹͕ੜ͡Δ • ϩάΞτͯ͠ϩάΠϯঢ়ଶͷΩϟογϡ͕දࣔ͞ΕΔ • ༗ྉձһʹͳͬͯແྉձһ࣌ͷΩϟογϡ͕දࣔ͞ΕΔ etc…
Pre-cache – Ωϟογϡͷಉظ • ϩάΠϯ/ϩάΞτΛݕͯ͠Ωϟογϡআ • ձһঢ়ଶΛࢹͯ͠ɺมԽ͕͋ͬͨΒΩϟογϡআ Ϣʔβ͕ ༗ྉձһԽ ϒϥβ
Service Worker Auth Status API purge ݖݶͷมԽΛݕ
Resource Hints • ࣍ʹඞཁͱͳΔϦιʔεΛࣄલʹ४උ͢ΔͨΊͷAPI • dns-prefetch: DNSʹΑΔ໊લղܾΛࣄલʹߦ͏ • preconnect :
TCPଓΛࣄલʹߦ͏ • prefetch : ࣄલʹίϯςϯπΛऔಘͯ͠Ωϟογϡ • prerender : ϖʔδશମΛࣄલʹϨϯμϦϯά ྫ: <link rel="preconnect" href="//example.com">
Resource Hints - ே༦ץϖʔδͷprefetch • ϢʔβͷಡΜͰ͍Δ໘ͷ࣍ͷ໘Λprefetch • URLݻఆɾϦιʔε͕੩తͳͷͰprefetch͍͢͠ Prefetchແ͠: ServerSide+Clientͷoverhead
Prefetch༗Γ: overheadແ͠
Resource Hints – ֎෦ίϯςϯπͷpreconnect • ࠂͷ֎෦ίϯςϯπͰར༻͞ΕΔυϝΠϯpreconnect • ίϯςϯπURL͕ಈతͰprefetchͮ͠Β͍ : DNSʹΑΔ໊લղܾ
ᒵ: TCP handshake ࢵ: SSL handshake փ: ࣮σʔλͷऔಘ
Resource Hints – ಈతͳprerender • Ϣʔβ͕࣍ʹ։͜͏ͱ͍ͯ͠ΔϖʔδΛprerender • ϚεΧʔιϧ͕ϦϯΫʹ͍ۙͮͨΒlinkλάΛૠೖ • λϒΓସ͑ͱಉ͡ͰϖʔδભҠ
LinkλάΛૠೖ
ϑΝʔετϏϡʔදࣔͷ࠷దԽ – PRPLύλʔϯ • Push: ϑΝʔετϏϡʔͷඳըʹඞཁͳϦιʔεΛPush • Render: ϑΝʔετϏϡʔΛඳը •
Pre-cache: ࣍ʹඞཁͳϦιʔεϖʔδΛPre-cache • Lazyload: ϑΝʔετϏϡʔ֎ͷίϯςϯπΛLazyload *Googleͷఏএ͢ΔSPAΛલఏͱͨ͠PRPLύλʔϯͱҟͳΔͷͷࢀߟʹ͍ͯ͠Δ
Lazyload ϑΝʔετϏϡʔपลͷΈಡΈࠐΈ PlaceholderΛૠೖ ࣮σʔλΛಡΈࠐΈ • DOMϊʔυͷେ͖͞ɾਂ͞Λ͑ͯߴԽ
ύϑΥʔϚϯεϞχλϦϯά • ϑΝΠϧαΠζϨϯμϦϯάऴྃ࣌ؒͳͲΛࢹ • Ұఆͷਫ४ΛԼճͬͨΒslackʹ௨
Reliable
ΦϑϥΠϯͰهࣄ͕ӾཡͰ͖Δ ϒϥβ Service Worker Cache Network Offlineͷ߹ ServiceWorkerͷΩϟογϡฦ͢
ΦϑϥΠϯͰϢʔβߦಈΛτϥοΩϯάͰ͖Δ • Background Sync • ΦϑϥΠϯ࣌ʹૹ৴ͨ͠ϦΫΤετΛΦϯϥΠϯ෮ؼ࣌ʹ࠶ૹ • τϥοΩϯά༻ͷσʔλΛBackground SyncͰૹ৴ •
ΦϑϥΠϯ࣌ͷهࣄอଘɾίϝϯτߘͳͲʹԠ༻Մೳ ϦΫΤετΛ อଘ ϒϥβ Indexed DB Server Service Worker Background Sync ͷొ ΦϯϥΠϯ෮ؼ·Ͱػ ϦΫΤετΛ ૹ৴
Engaging
ϗʔϜը໘ͷՃ • ϫϯλοϓͰΞΫηεՄೳ • ωΠςΟϒΞϓϦͬΆ͍ݟͨ web manifestΛొ͢ΔͱϗʔϜը໘ొՄೳ
ϗʔϜը໘ͷՃ • ϗʔϜը໘͔Βىಈ͞Εͨ߹ʹΩϟογϡྔ૿͢ • ΑΓαΫαΫಈ͔ͨ͢Ί • ϗʔϜը໘͔Βͷىಈnavigator.standaloneͰผՄೳ
Push௨ • ใ௨ʹར༻ • एϝʔϧΑΓ։෧͕ߴ͍ • ػցֶशʹΑΔΫϦοΫ࠷େԽ ͳͲΛݕ౼த
Service Workerͷ։ൃ
Workboxͷஔ͖͑ • ࠷ۙ·ͰϑϧεΫϥονͰॻ͍͍͕ͯͨϝϯς͕͖͍ͭ • ΩϟογϡͷTTLͳͲɺΩϟογϡཧશͯࣗྗ࣮ • IDBͬͯtimestampཧ͢Δͷͱ͔໘… GoogleͷServiceWorker։ൃ༻ͷϥΠϒϥϦɾπʔϧ
WorkboxͰग़དྷΔ͜ͱ – TTLͷ࣮ྫ WorkboxΛར༻͠ͳ͍߹ WorkboxΛར༻ͨ͠߹
WorkboxͰग़དྷΔ͜ͱ • SWͰΓ͍ͨجຊతͳࣄ֓Ͷ࣮͞Ε͍ͯΔ • Precaching • Runtime caching • Cache
Strategies (stale-while-revalidateͱ͔) • Request routing • Background sync • ϩά͕Ͱڍಈ͕ͱͯΘ͔Γ͍͢
ServiceWorkerͷςετ • seleniumͰෳϒϥβͰͷࣗಈςετΛ࣮ߦ • ServiceWorker༻ͷUnit/E2EςετϔϧύΛར༻ • https://github.com/GoogleChromeLabs/sw-testing-helpers • Ͱ͏ϝϯς͞Εͯͳͦ͞͏…
·ͱΊ • ܦిࢠ൛PWAԽͰCVRɾDAUଟ͘ͷࢦඪ͕վળͨ͠ • PWAԽͰϑΝʔετϏϡʔͷදࣔΛॏࢹ • දࣔվળͰPRPLύλʔϯΛࢀߟ • ύϑΥʔϚϯεܧଓతʹվળ͕ඞཁ •
ServiceWorker։ൃͰworkboxsw-testing-helper͕ศར
͋Γ͕ͱ͏͍͟͝·ͨ͠