Slide 1

Slide 1 text

ISOMORPHIC APPLICATIONͷ ύϑΥʔϚϯεɾνϡʔχϯά Ξϝϒϩ ި ඾ @ CYBERAGENT

Slide 2

Slide 2 text

ࣗݾ঺հ ިɹ඾ʢί΢ɹώϯʣɹ 32࠽ ▸ ത࢜ʢ޻ֶʣ ▸ ग़਎ɿதࠃɾྒྷೡʢ౦๺஍ํʣ ▸ גࣜձࣾαΠόʔΤʔδΣϯτ
 Ξϝʔόϒϩά ϑϩϯτϦχϡʔΞϧͷج൫ɾӡ༻Λ୲౰ ▸ 2014೥4݄ɹגࣜձࣾαΠόʔΤʔδΣϯτɹ৽ଔೖࣾ
 2014೥5݄ɹϓϥοτϑΥʔϜɹαʔόʔΤϯδχΞʢJavaʣ
 2015೥4݄ɹ৽نϓϩδΣΫτɹαʔόʔΤϯδχΞʢGoʣ
 2015೥9݄ɹAmeba Ownd ɹɹ ϑϩϯτΤϯδχΞʢAngularJSʣ
 2016೥1݄ɹΞϝʔόϒϩάɹɹϑϩϯτΤϯδχΞʢReact + Node.jsʣɹ ▸ https://twitter.com/houbin217jz ▸ https://github.com/kouhin

Slide 3

Slide 3 text

ΞϝʔόϒϩάɾSPϦχϡʔΞϧ ▸ 2016೥8݄ϦϦʔε ▸ ಺༰ɿ ▸ Javaϕʔε
 →ɹNode.js ▸ Server side renderingʢSSRʣ
 →ɹIsomorphic App (SSR + SPA)
 React + Redux + React Router ▸ σβΠϯϦχϡʔΞϧ ▸ ӡ༻ͳͲʢhttp://www.atmarkit.co.jp/ ait/articles/1704/13/news017.htmlʣ ΞϝʔόϒϩάɾSPϦχϡʔΞϧ https://developers.cyberagent.co.jp/blog/archives/636/

Slide 4

Slide 4 text

ΞϝʔόϒϩάɾSPϦχϡʔΞϧ ISOMORPHIC APPLICATIONύʔϑΥʔϚϯεɾνϡʔχϯά ▸ όοΫΤϯυͷΩϟογϡ ▸ ஗Ԇϩʔυ & ίʔυ෼ׂ ▸ Service Worker & ΞηοτͷϓϦΩϟογϡ)

Slide 5

Slide 5 text

όοΫΤϯυ ͷΩϟογϡʂ

Slide 6

Slide 6 text

όοΫΤϯυͷΩϟογϡ ͳͥόοΫΤϯυͷΩϟογϡ͕ॏཁͳͷ͔ - 1 ▸ SSRͷύϑΥʔϚϯε͕ྑ͘ͳ͍ʂ ▸ ݪҼɿैདྷSPA޲͚ͷٕज़ΛαʔόʔͰ࣮ݱ
 ϨϯμϦϯάॲཧ͕ෳࡶ
 Perf (SSR React) < Perf (Template, e.g. Handlebars.js)

Slide 7

Slide 7 text

ϨϯμϦϯάॲ ཧ͕ෳࡶͰɺαʔ όʔʹͱͬͯύ ϑΥʔϚϯε͕ ѱ͍

Slide 8

Slide 8 text

όοΫΤϯυͷΩϟογϡ ͳͥΩϟογϡ͕ॏཁͳͷ͔ - 2 ▸ αʔόʔͷύϑΥʔϚϯε͸ಛʹॏཁ ▸ ཧ༝: ͢΂ͯͷϢʔβʔʹαʔϏεΛఏڙ SPA͕ಈ͔ͳͯ͘΋
 - Өڹൣғ͸֘౰ϢʔβʔͷΈ
 - ैདྷͷSSRͱ΄΅ಉ͘͡ӾཡͰ ͖Δɻ

Slide 9

Slide 9 text

όοΫΤϯυͷΩϟογϡ ͳͥΩϟογϡ͕ॏཁͳͷ͔ - 3 ▸ Ωϟογϡ͕ޮ͖΍͍͢ ▸ ཧ༝: SEOΛॏࢹ͢ΔӾཡܥͷγεςϜ ί΢͘Μɺί΢͘ΜɺISOMORPHICͷ͜ͱΛฉ͖͍ͨͰ͚͢Ͳ ͲΜͳγεςϜͰ͔͢ ͏ͪͷ؅ཧγεςϜͰ͢ ͑ͬͬʁʁͲ͏ͯ͠ISOMORPHICͳͷʁ ΧοίΠΠ͔Β ͦΕ͸ISOMORPHICΛ΍Ίͨ΄͏͕͍͍

Slide 10

Slide 10 text

όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ ໰୊఺Λચ͍ग़͢ ▸ ԿΛΩϟογϡ͢Δ ▸ Ωϟογϡอଘ͢ΔλΠϛϯά ▸ Ωϟογϡ࡟আ͢ΔλΠϛϯά ▸ Local Cache VS Cache Server

Slide 11

Slide 11 text

όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ ΞϝϒϩSSRͷྲྀΕ ▸ PathϚονϯάɺίϯϙωϯ τͱඞཁͳॲཧΛऔΓग़͢ ▸ Redux Store४උ: APIίʔϧ ΛؚΊɺඞཁͳσʔλॲཧ Λߦ͏‼ ▸ Redux Store + ReactDOMServer.renderTo String()‼ = HTML ▸ Q1. ԿΛΩϟογϡ͢Δ 
 
 
 ߋ৽ස౓͕௿͍Object
 
 
 ReactDOMServer
 .renderToString() ͷ݁Ռ

Slide 12

Slide 12 text

όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ ԿΛΩϟογϡ͢Δ: ReactDOMServer.renderToString() ▸ ΫϥΠΤϯτʹΑͬͯಈతʹมΘΔ಺༰͕͋ΔͷͰɺੜ੒͞ΕͨHTMLΛͦͷ· ·࢖͑ͳ͍ ReactDOMServer.renderToString() Template Create Template Template + Client Info (e.g. user-agent) = HTML Cache

Slide 13

Slide 13 text

όοΫΤϯυͷΩϟογϡ ͪͳΈʹ ▸ ΞϝϒϩͰ͸Ұ൪࠷ॳʹHTML(ReactDOMServer
 .renderToString) ͷΩϟογϡΛͪΌΜͱ࣮૷͕ͨ͠ɺAPI/ ObjectͷΩϟογϡʹ͍ͭͯ͋·Γॏࢹ͠ͳ͔ͬͨɻ ▸ 6݄ͷτϐοΫεͷ͖͔͚ͬͰAPI/ObjectΛਫ਼ࠪ͠ɺΩϟο γϡΛ͖ͪΜͱ࣮૷ͯ͠ɺ͔ͳΓྑ͍݁Ռ͕ग़ͨɻ

Slide 14

Slide 14 text

όοΫΤϯυͷΩϟογϡ ໷ϐʔΫଳͷฏۉϨεϙϯελΠϜ Before: 26ms After: 17ms API/Object Cache࣮૷લޙͷൺֱ

Slide 15

Slide 15 text

όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q2. ΩϟογϡอଘλΠϛϯά ▸ ΞΫηε͢Δͱ͖ʹɺΩϟογϡ͕ݟ͔ͭΒͳ͔ͬͨΒɺ ॲཧͯ͠Ωϟογϡอଘ͢Δɻ

Slide 16

Slide 16 text

όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q3. Ωϟογϡ࡟আλΠϛϯά ▸ هࣄΛߋ৽͞ΕͨΒɺهࣄIDΛ΋ΒͬͯهࣄͷΩϟο γϡΛ࡟আ͢Ε͹OK ͜Ε͸μϝʂʂ

Slide 17

Slide 17 text

όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q3. Ωϟογϡ͔Β࡟আλΠϛϯά ▸ هࣄΛߋ৽͞ΕͨΒɺهࣄIDΛ΋ΒͬͯهࣄͷΩϟογϡΛ࡟আ͢Ε͹OK ʢ͜Ε͸μϝʂʣ ▸ هࣄͷߋ৽
 ˠɹهࣄϖʔδͷΩϟογϡΛ࡟আ ▸ هࣄͷ౤ߘ
 ˠɹهࣄҰཡͷΩϟογϡΛ࡟আ
 ˠɹهࣄৄࡉͷϦϯΫΛߋ৽͠ͳ͍ͱ͍͚ͳ͍ͷͰɺهࣄৄࡉͷΩϟογϡΛ࡟আ͢Δඞཁ͕͋Δ ▸ εΩϯɾϓϩϑΟʔϧͷߋ৽
 ˠɹϒϩΨʔͷશϖʔδͷΩϟγϡΛ࡟আ ࣮૷͸ෳࡶʹͳΔ͠ɺ
 ສ͕ҰΩϟογϡͷ࡟আ͕࿙ΕͨΒɺ͜Θ͍ʂʂʂʂʂ

Slide 18

Slide 18 text

όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q3. Ωϟογϡ͔Β࡟আλΠϛϯά ▸ Namespace (Ameba ID)ຖΛ࡟আ
 ▸ Fallback: ΩϟογϡͷTTLΛઃఆ 
 ສ͕Ұ࡟আࣦഊͯ͠΋ɺTTLʹΑΓΩϟογϡΛࣦޮͤ͞Δ namespace: “staff”
 https://ameblo.jp/staff 
 https://ameblo.jp/staff/message-board.html
 https://ameblo.jp/staff/entry-12308025976.html
 https://ameblo.jp/staff/** DELETE /cache?amebaId=staff

Slide 19

Slide 19 text

▸ Q3. Ωϟογϡ͔Β࡟আλΠϛϯά ▸ τϥϯβΫγϣϯ໰୊ όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ߋ৽ user_a DELETE 
 /cache?
 ameba_id = user_a user_b API Server Node.js Server Cache Ӿཡ Rendering Evict Cache /ameba_id Save Ωϟογϡ࡟আ
 ࣦഊʂ

Slide 20

Slide 20 text

▸ Q3. Ωϟογϡ͔Β࡟আλΠϛϯά ▸ τϥϯβΫγϣϯ໰୊ʢόʔδϣϯ෇͖ʣ όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ߋ৽ user_a DELETE 
 /cache?
 ameba_id = user_a user_b API Server Node.js Server Cache Ӿཡ Rendering Update user_a/version: 4 Save to /user_a/3/ GET user_a/version: 3

Slide 21

Slide 21 text

όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q4. Local Cache VS Cache Server ▸ Node.jsͷΠϯελϯε਺͕ଟ͍ ▸ αʔϏε಺ʹॏෳϨϯμϦϯάͨ͘͠ͳ͍͔Β
 Ұ൪࠷ॳʹϦΫΤετΛड͚औͬͨαʔόʔ͕Ωϟογϡ͞Εͨ΋ͷΛଞͷαʔ όʔʹڞ༗Ͱ͖Δ → Cache Server͕ඞཁ ▸ On-memory͸ૣ͍Ͱ͔͢ΒɺΑ͘࢖ΘΕΔ΋ͷΛOn-memoryʹ΋อଘ͢Δ (LRU-cache) → Local Cache͕ඞཁ ▸ 2֊૚: On-memory Cache (LRU-cache) + Cache Server

Slide 22

Slide 22 text

όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Ωϟογϡͷઃܭͷ·ͱΊ ▸ HTMLςϯϓϨʔτ + APIͷσʔλΩϟογϡ ▸ Namespace (AmebaId + Version) ͰΩϟογϡอଘɾΞ ΫςΟϒతͳ࡟আ(Versionߋ৽) ▸ On-memory cache + Cache Server 2֊૚

Slide 23

Slide 23 text

όοΫΤϯυͷΩϟογϡ Ξϝϒϩ όοΫΤϯυΩϟογϡͷશମਤ

Slide 24

Slide 24 text

όοΫΤϯυͷΩϟογϡ ݁Ռ1: NEW RELICͰهࣄৄࡉͷΩϟογϡঢ়گ Cache Hit!

Slide 25

Slide 25 text

όοΫΤϯυͷΩϟογϡ ݁Ռ2: NEW RELICͰهࣄҰཡͷΩϟογϡঢ়گ Cache Hit!

Slide 26

Slide 26 text

όοΫΤϯυͷΩϟογϡ ݁Ռ3: DATADOGͷMEMCACHED HIT RATE

Slide 27

Slide 27 text

஗Ԇϩʔυ LAZY LOAD

Slide 28

Slide 28 text

஗Ԇϩʔυ ஗Ԇϩʔυ ▸ ద੾ͳλΠϛϯάͰద੾ͳॲཧΛߦ͏ ▸ SSR → SPA ▸ ϖʔδͷ্ → ϖʔδͷԼ ▸ ίʔυͷ஗ԆධՁ: ίʔυ෼ׂ

Slide 29

Slide 29 text

஗Ԇϩʔυ ஗Ԇϩʔυ: SSR → SPA ▸ SSRͷྲྀΕ ▸ PathϚονϯάɺίϯϙωϯ τͱඞཁͳॲཧΛऔΓग़͢ ▸ Redux Store४උ: APIίʔϧ ΛؚΊɺඞཁͳσʔλॲཧ Λߦ͏ ▸ Redux Store + ReactDOMServer.renderTo String() = HTML https://github.com/kouhin/react-router-hook https://github.com/kouhin/rrr-lazy

Slide 30

Slide 30 text

஗Ԇϩʔυ ஗Ԇϩʔυ: ϖʔδͷ্ → ϖʔδͷԼ

Slide 31

Slide 31 text

஗Ԇϩʔυ ͔ͤͬ͘αʔόʔ͔ΒϑϩϯτʹདྷͨͷͰɺ
 CHROME DEV TOOLͰύϑΥʔϚϯεΛΈͯΈΑ͏ʂ ϖʔδʹؔ܎ͳ͍Ϟ δϡʔϧ΋ϩʔυ͠ ͯ͠·ͬͯɺJSධՁ ͕࣌ؒ௕͘ͳͬͨ

Slide 32

Slide 32 text

ίʔυ෼ׂ ίʔυ෼ׂͷϝϦοτ ▸ ඞཁ͸ͳ͍ίϯϙωϯτΛϩʔυ͠ͳ͍Α͏ʹ ▸ JSධՁ͕࣌ؒ୹͘ͳΔ ▸ main.js๲େԽΛ๷͙ ▸ ৽͍͠ػೳΛͲΜͲΜ௥Ճͯ͠OK

Slide 33

Slide 33 text

ίʔυ෼ׂ ίʔυ෼ׂͷํ๏ ▸ Webpack ▸ ෼ׂཻ౓ɿAtomicσβΠϯ ͷ Organismsຖ ▸ ෼ׂ͞ΕͨBundleͷαΠζΛݮΒ͢ϓϥάΠϯ ▸ ModuleConcatenationPlugin ▸ AggressiveMergingPlugin

Slide 34

Slide 34 text

ίʔυ෼ׂ ίʔυ෼ׂͷํ๏ɿWEBPACK ▸ https://webpack.js.org/guides/code-splitting ▸ require.ensure, bundle loader, Dynamic imports() ▸ ΞϝϒϩɿDynamic imports()
 Lazy Loadʹ͍ͨ͠৔߹: 
 const loadExample = () => import(‘./ExampleComponent’)

Slide 35

Slide 35 text

ίʔυ෼ׂ ίʔυ෼ׂͷํ๏ɿཻ౓ ▸ AtomicσβΠϯ: Organismsຖ هࣄҰཡTemplate AtomicσβΠϯ

Slide 36

Slide 36 text

ίʔυ෼ׂ ίʔυ෼ׂͷํ๏ɿཻ౓ ▸ AtomσβΠϯ: Organisms୯Ґ هࣄҰཡTemplate rrr--lazy΋Dynamic Import()ʹରԠࡁΈ

Slide 37

Slide 37 text

ίʔυ෼ׂ ݁Ռ1ɿ࣮ࡍͷಈ͖

Slide 38

Slide 38 text

ίʔυ෼ׂ ݁Ռ2ɿJSධՁ࣌ؒ

Slide 39

Slide 39 text

ίʔυ෼ׂ ίʔυ෼ׂͷҰ൪େ͖͍σϝϦοτ ▸ ݱ࣌఺ͰWebpackͷ࠶Ϗϧυ଎౓͕͔ͳΓ஗͍ʂ ▸ ϩʔΧϧͷ։ൃϞʔυͰίʔυΛमਖ਼ͨ͠Βɺ10s - 20s ͔͔Δ ▸ ղܾํ๏ɿϩʔΧϧͰίʔυ෼ׂΛແޮʹ͢Δ ▸ babel-plugin-dynamic-import-webpack
 babel-plugin-remove-webpack


Slide 40

Slide 40 text

ίʔυ෼ׂͯ͠΋ɺΞηοτ ͷαΠζ͸΍͸Γେ͖͍ʂʂ

Slide 41

Slide 41 text

SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER ▸ લఏɿHTTPSʂ ▸ Ξϝϒϩ2017 – େن໛αʔϏεhttpsԽ ~ All GreenΛ໨ ࢦͯ͠ ~
 https://developers.cyberagent.co.jp/blog/archives/7743

Slide 42

Slide 42 text

SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER ▸ service-worker.jsΠϯετʔϧλΠϛϯά ▸ AMPϖʔδʹΞΫηε ▸ ΞϝϒϩSPϖʔδʹΞΫηε

Slide 43

Slide 43 text

SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER - ΤϯτϦ ▸ AMPϖʔδɿඞཁͳΞηοτΛϓϦϩʔυɾΩϟογϡ
 Install-service-worker.html service-worker.js
 (installer) service-worker.js
 (CDN) ΫϩευϝΠϯ importScripts Assets

Slide 44

Slide 44 text

SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER - ΤϯτϦ ▸ ΞϝϒϩSPϖʔδɿΞηοτΛΩϟογϡ service-worker.js
 (installer) service-worker.js
 (CDN) ΫϩευϝΠϯ importScripts Assets

Slide 45

Slide 45 text

SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER - ࣮૷ ▸ Webpack + Workbox
 
 https://github.com/GoogleChrome/workbox

Slide 46

Slide 46 text

݁Ռ͸ʁ

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

কདྷͷల๬ কདྷͷల๬ ▸ React 16 & SSR ▸ HTTP/2 & ίʔυ෼ׂ ▸ PWA & Service Worker

Slide 49

Slide 49 text

কདྷͷల๬ REACT 16 & SSR ▸ Ұ൪ظ଴͍ͯ͠Δͷ͸SSRύϑΥʔϚϯεͷվળ React 15 ϚΠϯεϨουΛϒϩο Ϋ͞ΕΔͷͰɺ ݱࡏϚϧνϓϩηεͰ ϨϯμϦϯά͍ͯ͠Δ

Slide 50

Slide 50 text

কདྷͷల๬ REACT 16 ▸ Ұ൪ظ଴͍ͯ͠Δͷ͸SSRύϑΥʔϚϯεͷվળ React 16

Slide 51

Slide 51 text

▸ ݱঢ়ɿChromeͳͲ͸ಉ࣌ʹૹ৴͢ΔϦΫΤετ͸6ͭ·Ͱ ʹ੍ݶ͞Ε͍ͯΔ͔Βɺ෼ׂ͞ΕͨJSϑΝΠϧΛಉ࣌ʹϩʔ υ͢ΔࡍʹϒϩοΫ͞Εͯ͠·͏ɻ ▸ ࠓޙɿHTTP/2 ετϦʔϜͷଟॏԽΛར༻͠ɺύϑΥʔϚϯ ε޲্ কདྷͷల๬ HTTP/2 & ίʔυ෼ׂ

Slide 52

Slide 52 text

কདྷͷల๬ PWA & SERVICE WORKER ▸ ݱঢ়: Service Worker = ϓϦΩϟογϡ ▸ ࠓޙ ▸ Add to Home Screen ▸ App ShellϞσϧ ▸ ΦϑϥΠϯϞʔυ ▸ ௨஌

Slide 53

Slide 53 text

͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠