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
370
日経電子版への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.2k
Microservices on Fastly
ryysd
42
22k
Other Decks in Programming
See All in Programming
「10分以内に機能を消せる状態」 の実現のためにやっていること
togishima
1
530
「AWS CDK入門」の前日譚/Prequelto-Introduction-To-AWSCDK
tyumugi1113
0
100
Module Harmony
petamoriken
2
500
Feature Flags Suck! - KubeCon Atlanta 2025
phodgson
0
150
チーム開発の “地ならし"
konifar
8
5.7k
生成AIを活用したリファクタリング実践 ~コードスメルをなくすためのアプローチ
raedion
0
110
目的で駆動する、AI時代のアーキテクチャ設計 / purpose-driven-architecture
minodriven
9
3.1k
PHPライセンス変更の議論を通じて学ぶOSSライセンスの基礎
matsuo_atsushi
0
170
AIエージェントでのJava開発がはかどるMCPをAIを使って開発してみた / java mcp for jjug
kishida
4
750
例外処理を理解して、設計段階からエラーを見つけやすく、起こりにくく #phpconfuk
kajitack
12
6.3k
物流DXを支える“意味”の設計:セマンティックレイヤーとAIで挑むデータ基盤/登壇資料(飯塚 大地)
hacobu
PRO
0
110
「正規表現をつくる」をつくる / make "make regex"
makenowjust
1
700
Featured
See All Featured
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
253
22k
Into the Great Unknown - MozCon
thekraken
40
2.2k
Large-scale JavaScript Application Architecture
addyosmani
514
110k
Code Review Best Practice
trishagee
72
19k
KATA
mclloyd
PRO
32
15k
Designing for humans not robots
tammielis
254
26k
GraphQLとの向き合い方2022年版
quramy
49
14k
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
The Language of Interfaces
destraynor
162
25k
Faster Mobile Websites
deanohume
310
31k
Done Done
chrislema
186
16k
Making Projects Easy
brettharned
120
6.5k
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͕ศར
͋Γ͕ͱ͏͍͟͝·ͨ͠