Slide 1

Slide 1 text

SSR / BFF ʹ͍ͭͯ Mercari Web / Frontend meetup #1 2018/02/19

Slide 2

Slide 2 text

Twitter: @yosuke_furukawa Github: yosuke-furukawa

Slide 3

Slide 3 text

/PEFֶԂ࣌ݶ໨΍ΔͷͰօ͞Μ དྷͯͶʂʂʂ

Slide 4

Slide 4 text

࠷ۙBFFʹ͍ͭͯͷ࿩Λ ͱ͋ΔϝσΟΞʹॻ͍ͯΔ

Slide 5

Slide 5 text

͓ͦΒۙ͘೔ެ։༧ఆ ʢక੾ʹؒʹ߹͑͹ʣ

Slide 6

Slide 6 text

ࠓ೔ͷ࿩ • BFFೖ໳ • SSRೖ໳ • BFF/SSR࣮ફྫs

Slide 7

Slide 7 text

Α͋͘Δٙ໰ • BFFͬͯͳΜͷͨΊʹ͍Δͷʁ • SSRͬͯSEOෆཁͳΒཁΒͳ͍Μ͡Όͳ͍ʁ • BFF/SSRͬͯ೉͘͠ͳ͍ͷʁ

Slide 8

Slide 8 text

BFFೖ໳

Slide 9

Slide 9 text

BFFͱ͸Կ͔ • Backends For Frontends • ϑϩϯτΤϯυͷͨΊͷόοΫΤϯυ(αʔό) ͷ͜ͱ ͜͜ʂ

Slide 10

Slide 10 text

Q. ͳΜͰBFF͕ඞཁͳͷ͔

Slide 11

Slide 11 text

Q. ͳΜͰBFF͕ඞཁͳͷ͔ A. 2ͭ͋Δ 1. ૊৫తͳ࿩ 2. ੑೳతͳ࿩

Slide 12

Slide 12 text

Q. ͳΜͰBFF͕ඞཁͳͷ͔ A. 2ͭ͋Δ 1. ૊৫తͳ࿩ 2. ੑೳతͳ࿩ (SSRͷ࿩)

Slide 13

Slide 13 text

BFFͷ૊৫తͳ࿩ • ͜Ε·ͰͷWebΞϓϦέʔγϣϯ • ҰຕؠͰͰ͖ͨΞϓϦέʔγϣϯ • HTMLςϯϓϨʔτͰදࣔΛߏங • ߋ৽͸FormͰ

Slide 14

Slide 14 text

BFFͷ૊৫తͳ࿩ • ঃʑʹͦΕ͚ͩͰ͸ճΒͳ͘ͳ͖͍ͬͯͯΔ • Ajax௨৴ͰΠϯλϥΫςΟϒʹ • Ϟʔμϧ΍υϥοάΛۦ࢖ͨ͠ϦονͳΠϯ λϑΣʔεʹ

Slide 15

Slide 15 text

BFFͷ૊৫తͳ࿩ • ঃʑʹͦΕ͚ͩͰ͸ճΒͳ͘ͳ͖͍ͬͯͯΔ • Ajax௨৴ͰΠϯλϥΫςΟϒʹ • Ϟʔμϧ΍υϥοάΛۦ࢖ͨ͠ϦονͳΠϯ λϑΣʔεʹ

Slide 16

Slide 16 text

ͦΕΛಥ͖ਐΊͨઌʹ͋Δ ҉ࠇͷUI • JSP(Java ͷ HTMLςϯϓϨʔτ)͔ΒJavaScriptΛݺ ͼग़͢ʂʂʂ • JavaScriptͰDOMͷதͰΰϦΰϦͷϩδοΫΛॻ ͘ʂʂʂ • Ajax௨৴தʹDOMͰΠϯδέʔλग़͍͔ͨ͠Βͬͯ શ෦ͷૢ࡞ͰAjax௨৴தʹΠϯδέʔλग़͢ʂʂʂ

Slide 17

Slide 17 text

ͦΕΛಥ͖ਐΊͨઌʹ͋Δ ҉ࠇͷUI • JSP(Java ͷ HTMLςϯϓϨʔτ)͔ΒJavaScriptΛ ݺͼग़͢ʂʂʂ • JavaScriptͰDOMͷதͰϩδοΫΛॻ͘ʂʂʂ • Ajax௨৴தʹDOMͰΠϯδέʔλग़͍͔ͨ͠Βͬ ͯશ෦ͷૢ࡞ͰAjax௨৴தʹΠϯδέʔλग़ ͢ʂʂʂ=>ফ͑ͳ͘ͳΔΠϯδέʔλ΁

Slide 18

Slide 18 text

ͦΕΛಥ͖ਐΊͨઌʹ͋Δ ҉ࠇͷUI • JSP(Java ͷ HTMLςϯϓϨʔτ)͔ΒJavaScriptΛ ݺͼग़͢ʂʂʂ • JavaScriptͰDOMͷதͰϩδοΫΛॻ͘ʂʂʂ • Ajax௨৴தʹDOMͰΠϯδέʔλग़͍͔ͨ͠ Βͬͯશ෦ͷૢ࡞ͰAjax௨৴தʹΠϯδέʔλग़ ͢ʂʂʂ

Slide 19

Slide 19 text

BFFͷ૊৫తͳ࿩ • ΋͏͍͍Ճݮʹ GUI (ϖʔδ) Λ࡞ΔॴͱσʔλΛ؅ ཧ͢Δॴ͸෼͚͍ͨɻ • WebΞϓϦέʔγϣϯϑϨʔϜϫʔΫ͔ͩΒͱ͍ͬ ͯԿͰ΋΍ΔͷͰ͸ͳ͘ɺݖݶΛ෼཭͍ͨ͠ɻ • σʔλΛ؅ཧ͢Δॴ͸όοΫΤϯυͰ࣮ࢪ͍ͨ͠ • GUI(ϖʔδ)Λ࡞Δॴ͸ϑϩϯτΤϯυͰ࣮ࢪ͍ͨ͠

Slide 20

Slide 20 text

BFFͷ૊৫తͳ࿩

Slide 21

Slide 21 text

BFFͷ૊৫తͳ࿩ όοΫΤϯυ ΤϯδχΞ͸σʔλ ͷૢ࡞ɾ؅ཧʹूத ͢Δɻ

Slide 22

Slide 22 text

BFFͷ૊৫తͳ࿩ ϑϩϯτΤϯυ ΤϯδχΞ͸(6* ͷߏஙʹઐ೦͢Δɻ ओͳ࢓ࣄ͸6*69ͷ ޲্

Slide 23

Slide 23 text

BFFͷྺ࢙తͳ࿩ • ࠷ۙ "BFF" ͱ͍͏໊લ͕͍͚ͭͨͩͰಛʹ৽͍͠࿩Ͱ͸ ͳ͍ɻ • ੲͷΤϯλʔϓϥΠζ࣌୅͸͜͏͍͏ΞʔΩςΫνϟ͕ଟ ͔ͬͨ (๻΋લલ৬Ͱ͸ͦ͏ͩͬͨ) • HTML͕ࠓ·ͰԿ΋͠ͳͯ͘΋ϒϥ΢β͕উखʹGUIΛද ݱͯͨ͠ͷʹ๻Β͕SPAͱ͔ͰGUIΛ࠶ఆ͔ٛͩͨ͠͠Β ΋͏Ұ౓໊લ͕͍ͭͨ(ؾ͕͢Δ)ɻ

Slide 24

Slide 24 text

BFFͷྺ࢙తͳ࿩ • Chapter 5: Re-Architecting ϞϊϦεతͳΞʔΩςΫνϟͰ͸νʔϜ ͱͯ͠εέʔϧ͠ͳ͍ͱࢥͬͨΒɺϑϩ ϯτΤϯυͱόοΫΤϯυʹ෼͚Δɺ ΑΓίϯςΫετΛҙࣝͯ͠ϚΠΫϩ αʔϏεԽ͢ΔͷΛݕ౼͢Δ

Slide 25

Slide 25 text

BFFͷྺ࢙తͳ࿩ • Chapter 5: Re-Architecting ϞϊϦεతͳΞʔΩςΫνϟͰ͸νʔϜ ͱͯ͠εέʔϧ͠ͳ͍ͱࢥͬͨΒɺϑϩ ϯτΤϯυͱόοΫΤϯυʹ෼͚Δɺ ΑΓίϯςΫετΛҙࣝͯ͠ϚΠΫϩ αʔϏεԽ͢ΔͷΛݕ౼͢Δ ϑϩϯτΤϯυͱόοΫΤϯυʹ෼͚Δɺ ϚΠΫϩαʔϏεΛҙࣝ͢Δ

Slide 26

Slide 26 text

BFFͷྺ࢙తͳ࿩ • ྺ࢙తʹ͸ΞʔΩςΫνϟ͸ૄ݁߹ͱີ݁߹Λ ܁Γฦͯ͠༳Ε͍ͯΔɻ • લ·Ͱ͸ີ݁߹͕ͩͬͨɺ࠷ۙ͸ૄ݁߹ͷ͕ྑ ͘ͳ͖ͬͯͨɻ • ࠓޙ͸Ͳ͏ͳΔ͔Θ͔Βͳ͍ɺ·ͨີ݁߹ʹ໭ Δ͔΋͠Εͳ͍͠ɺૄ݁߹ͷ··͔΋͠Εͳ͍ɻ

Slide 27

Slide 27 text

SSRೖ໳

Slide 28

Slide 28 text

SSRͱ͸ • Server Side Rendering ͷུ • Client Side Ͱ HTML ΛϨϯμϦϯά͢Δ͜ͱ ΛClient Side RenderingͱݺͿɻͦΕʹର͠ ͯಉ͜͡ͱΛ Server Side Ͱ΋࣮ࢪ͢Δ͜ͱΛ Server Side Rendering ͱݺͿɻ

Slide 29

Slide 29 text

Server Side Rendering 4FSWFS 1BHF3FRVFTU $PNQPOFOUT 5FNQMBUFT 'FUDI%BUB %#"1* 3FOEFS)5.- (FUQBHFQBSUT

Slide 30

Slide 30 text

Server Side Rendering 4FSWFS 1BHF3FRVFTU $PNQPOFOUT 5FNQMBUFT 'FUDI%BUB %#"1* 3FOEFS)5.- $MJFOU4JEF 3FOEFSFS $PNQPOFOUT 5FNQMBUFT 3FOEFS)5.-XJUITBNF DMJFOUTFSWFSSFOEFSMPHJD 4FSWFS4JEF 3FOEFSFS (FUQBHFQBSUT

Slide 31

Slide 31 text

Why we need Server Side Rendering?

Slide 32

Slide 32 text

SEO

Slide 33

Slide 33 text

SEO

Slide 34

Slide 34 text

SEO Ϋϩʔϥ͕+4Λ࣮ߦͰ͖Δͱ͸ ͍͑ɺͦͷ+4͕ͪΌΜͱಈ͘อ ূ͸ͳ͍ɻ

Slide 35

Slide 35 text

SEO͸ॏཁɺͰ΋ຊ୊͸࣍

Slide 36

Slide 36 text

First View Performance

Slide 37

Slide 37 text

ͦ΋ͦ΋First ViewͱҰޱʹ ݴͬͯ΋छྨ͕͋Δ /BWJHBUJPO4UBSU 'JSTU1BJOU 'JSTU$POUFOUGVM 1BJOU Loading.. 'JSTU.FBOJOHGVM 1BJOU 'JSTU.FBOJOHGVM 1BJOU 7JTVBMMZSFBEZ *NBHF 5JNF5P *OUFSBDUJWF +4MPBEFE *NBHF 'VMMZ-PBEFE BMMSFTPVSDFTBSF MPBEFE *NBHF

Slide 38

Slide 38 text

First View Performance • SSR ʹ͓͚Δ First View ͷվળͱ͸ɺ͜ͷ First Meaningful Paint ·ͰΛࢦ͢ɻ /BWJHBUJPO4UBSU 'JSTU1BJOU 'JSTU$POUFOUGVM 1BJOU Loading.. 'JSTU.FBOJOHGVM 1BJOU

Slide 39

Slide 39 text

First View Performance • First Meaningful PaintҎ߱ͷվળ͸Service Worker΍HTTP2ͳͲผͳ΍Γํ͕͋Δɻ 'JSTU.FBOJOHGVM 1BJOU 7JTVBMMZSFBEZ *NBHF 5JNF5P *OUFSBDUJWF +4MPBEFE *NBHF 'VMMZ-PBEFE BMMSFTPVSDFTBSF MPBEFE *NBHF

Slide 40

Slide 40 text

Client Side Rendering ͷΈͰͷಈ͖

Slide 41

Slide 41 text

Client Side Rendering ͷΈͷ ৔߹ • First Meaningful Paint ͱ Time To Interact ͷ λΠϛϯά͕΄ͱΜͲಉ͡ɻ 'JSTU.FBOJOHGVM1BJOU 5JNF5P*OUFSBDUJWF +4MPBEFE 'JSTU$POUFOUGVM 1BJOU Loading..

Slide 42

Slide 42 text

Client Side Rendering ͷΈͷ ৔߹ • ݴ͍׵͑ΔͱɺFirst Contentful Paint͔ΒFirst Meaningful Paint ·Ͱ͕௕͘ͳΔɻ 'JSTU.FBOJOHGVM1BJOU 5JNF5P*OUFSBDUJWF +4MPBEFE 'JSTU$POUFOUGVM 1BJOU Loading..

Slide 43

Slide 43 text

Client Side Rendering ͷΈͷ ৔߹ • ݴ͍׵͑ΔͱɺFirst Contentful Paint͔ΒFirst Meaningful Paint ·Ͱ͕௕͘ͳΔɻ 'JSTU.FBOJOHGVM1BJOU 5JNF5P*OUFSBDUJWF +4MPBEFE 'JSTU$POUFOUGVM 1BJOU Loading.. Ϣʔβʔ͸ݟ͔͑ͯΒૢ࡞͢Δ 'JSTU.FBOJOHGVM1BJOU͕ग़͔ͯΒ*OUFSBDU ͢Δ ͷͰɺ͜ͷ$MJFOU4JEF3FOEFSJOH͚ͩͰ͸࣌ؒతʹແବ͕ଟ͍ɻ

Slide 44

Slide 44 text

ͦ͜Ͱ Server Side Rendering

Slide 45

Slide 45 text

/BWJHBUJPO4UBSU 'JSTU1BJOU 'JSTU$POUFOUGVM 1BJOU Loading.. 'JSTU.FBOJOHGVM 1BJOU ࠷ॳ͔ΒσʔλΛຒΊࠐΜͩঢ়ଶͰ)5.-ʹ͢Δ ʢ4FSWFS4JEF3FOEFSJOHʣ

Slide 46

Slide 46 text

ʮBFFΛಋೖ͢Δʯͱ͍͏࣌ ʹʮSSRʯ·Ͱηοτͷํ͕
 ϏδωεతͳϝϦοτ(ੑೳɺ SEO)΋આ໌͠΍͍͢ɻ

Slide 47

Slide 47 text

BFF/SSR࣮ફྫ

Slide 48

Slide 48 text

BFF/SSR࣮ફྫ • ฐࣾͷϘΠϥʔϓϨʔτΛߏங͠ɺͦΕΛల։͢ΔܗͰ֤։ ൃ͔Β࢖ͬͯ΋Β͍ͬͯΔ • bookingtable(ϨετϥϯݕࡧαΠτ)Ͱͷ࣮ફ (2016/11~) • raico(SNS)Ͱͷ࣮ફ (2016/12 ~) • coshigoto(ΞϯέʔτΞϓϦ)Ͱͷ࣮ફ (2017/08 ~) • AirShift(εέδϡʔϧ؅ཧΞϓϦ)Ͱͷ࣮ફ (2017/09 ~)

Slide 49

Slide 49 text

BFF/SSR࣮ફྫ • ฐࣾͷϘΠϥʔϓϨʔτΛߏங͠ɺͦΕΛల։͢ΔܗͰ֤։ ൃ͔Β࢖ͬͯ΋Β͍ͬͯΔ • bookingtable(ϨετϥϯݕࡧαΠτ)Ͱͷ࣮ફ (2016/11~) • raico(SNS)Ͱͷ࣮ફ (2016/12 ~) • coshigoto(ΞϯέʔτΞϓϦ)Ͱͷ࣮ફ (2017/08 ~) • AirShift(εέδϡʔϧ؅ཧΞϓϦ)Ͱͷ࣮ફ (2017/09 ~) ࣮ફճ਺ଟ਺ɺࠓޙ΋͍͔ͭ͘࠾༻༧ఆ

Slide 50

Slide 50 text

ฐࣾϘΠϥʔϓϨʔτ

Slide 51

Slide 51 text

redux-protoͱݺ͹ΕΔϘΠ ϥʔϓϨʔτΛ࡞ͬͯΔ • View: React • State Management: Redux • Component Management: Atomic Design • Redux Middleware: redux-effects, redux-async- loader, etc • SSR ready, Service Worker ready, AMP not yet

Slide 52

Slide 52 text

redux-protoͱݺ͹ΕΔϘΠ ϥʔϓϨʔτΛ࡞ͬͯΔ • View: React • State Management: Redux • Component Management: Atomic Design • Redux Middleware: redux-effects, redux-async- loader, etc • SSR ready, Service Worker ready, AMP not yet ϦΫϧʔτͷ-JWJOH"QQ4UBOEBSE ͱͯ͠։ൃத

Slide 53

Slide 53 text

redux-protoͱݺ͹ΕΔϘΠ ϥʔϓϨʔτΛ࡞ͬͯΔ • View: React • State Management: Redux • Component Management: Atomic Design • Redux Middleware: redux-effects, redux-async- loader, etc • SSR ready, Service Worker ready, AMP not yet ۙ೔ެ։͢Δʂʂʂʂ ͔΋

Slide 54

Slide 54 text

ฐࣾϘΠϥʔϓϨʔτ ͪΐͬͱ঺հ (React෼͔Δਓ޲͚)

Slide 55

Slide 55 text

ιʔείʔυϨΠΞ΢τ . !"" client // Client ͰͷΈ࣮ࢪ͢Δίʔυ܈ɺͪͳΈʹຊ౰ʹ਺ϑΝΠϧ͔͠ͳ͍ɻ # !"" analytics // Google Analytics ౳ͷղੳπʔϧ # $"" vendor // ֎෦ϕϯμʔͰClientͰͷΈ࣮ࢪ͢Δ΋ͷ !"" server // Server ͰͷΈ࣮ࢪ͢Δίʔυ܈ɻ # !"" components // SSRͷ࣌ͷίϯϙʔωϯτ # !"" configs // ίϯϑΟάϑΝΠϧ܈ # !"" libs // ·ͩnpmʹͳͬͯͳ͍ϥΠϒϥϦ܈ # !"" middlewares // SSRΛ࣮૷͍ͯ͠ΔίΞͷ෦෼ # $"" services // APIͷ·ͱΊΛߦ͍ͬͯΔαʔϏε૚ !"" shared # !"" components // atoms, molecules, organisms ͱ֊૚ʹͳͬͯΔɺSSR/CSR྆ํͰ࣮ࢪ # !"" redux // actions/reducersͰ͸෼͚ͯͳͯ͘ɺducksܗࣜͷϞδϡʔϧʹͳͬͯΔ # !"" routes // ϧʔλʔͷఆٛɺ͜͜Ͱ Code Splitting ͷઃఆ΋ߦ͍ͬͯΔ # !"" utils // ࡶଟͳ΋ͷ # $"" validators // Validation܈ !"" sw // Service Worker ϑΥϧμ $"" webpack // Webpack ϑΥϧμ

Slide 56

Slide 56 text

Atom Component export default compose( onlyUpdateForPropTypes, // PropTypesʹॻ͍ͨ΋ͷ͕มߋ͞Ε͚ͨ࣌ͩrendering͢Δ setPropTypes({ // PropTypesΛఆٛ loading: PropTypes.bool.isRequired, }), )(function Indicator(props) { const { loading } = props; if (!loading) { return null; } return (
); });

Slide 57

Slide 57 text

Flowͷ৔߹ // @flow import React from 'react'; import { compose, onlyUpdateForKeys } from 'recompose'; export default compose( onlyUpdateForKeys(), // FlowTypeͷ৔߹͸babel-pluginͰܕ৘ใΛύʔεͯ͠উ खʹshouldComponentUpdateΛ࣮ࢪ͢ΔϓϥάΠϯΛೖΕͯΔɻ )(function Foo(props: { foo: string, bar: number }) { const { foo, bar } = props; return (
{foo}-{bar}
); }); https://github.com/recruit-tech/babel-plugin-flow- onlyupdateforkeys

Slide 58

Slide 58 text

Flowͷ৔߹ // @flow import React from 'react'; import { compose, onlyUpdateForKeys } from 'recompose'; export default compose( onlyUpdateForKeys(), // FlowTypeͷ৔߹͸babel-pluginͰܕ৘ใΛύʔεͯ͠উ खʹshouldComponentUpdateΛ࣮ࢪ͢ΔϓϥάΠϯΛೖΕͯΔɻ )(function Foo(props: { foo: string, bar: number }) { const { foo, bar } = props; return (
{foo}-{bar}
); }); ܕ৘ใΛݩʹνϡʔχϯά͢Δ࢓૊ Έ͕ೖͬͯΔ https://github.com/recruit-tech/babel-plugin-flow- onlyupdateforkeys

Slide 59

Slide 59 text

Code Splitting using SSR import createUniversalComponent from ‘./createUniversalComponent’; const chunkName = ‘salon’; export function loadSalon(_, cb) { createUniversalComponent( () => import(/* webpackChunkName: “salon” */ ‘../components/organisms/Salon’), () => require.resolveWeak(‘../components/organisms/Salon’), chunkName, ).then((result) => cb(null, result), cb); } export function loadSalonForm(_, cb) { createUniversalComponent( () => import(/* webpackChunkName: “salon” */ ‘../components/organisms/SalonForm’), () => require.resolveWeak(‘../components/organisms/SalonForm’), chunkName, ).then((result) => cb(null, result), cb); } https://github.com/faceyspacey/react-universal- component

Slide 60

Slide 60 text

Code Splitting using SSR import createUniversalComponent from ‘./createUniversalComponent’; const chunkName = ‘salon’; export function loadSalon(_, cb) { createUniversalComponent( () => import(/* webpackChunkName: “salon” */ ‘../components/organisms/Salon’), () => require.resolveWeak(‘../components/organisms/Salon’), chunkName, ).then((result) => cb(null, result), cb); } export function loadSalonForm(_, cb) { createUniversalComponent( () => import(/* webpackChunkName: “salon” */ ‘../components/organisms/SalonForm’), () => require.resolveWeak(‘../components/organisms/SalonForm’), chunkName, ).then((result) => cb(null, result), cb); } https://github.com/faceyspacey/react-universal- component $PEF4QMJUͭͭ͠΋443ͷ࣌͸ී ௨ʹ+4$44ΛGFUDI͢Δ࢓૊Έ

Slide 61

Slide 61 text

Α͋͘Δٙ໰ • BFFͬͯͳΜͷͨΊʹ͍Δͷʁ
 => ݖݶͷ෼཭ͱ։ൃͷ͠΍͢͞ • SSRͬͯSEOෆཁͳΒཁΒͳ͍Μ͡Όͳ͍ʁ
 => No, First Meaningful PaintΛ࠷దԽ͢ΔͨΊʹ͸ඞཁ • BFF/SSRͬͯ೉͘͠ͳ͍ͷʁ
 => Partially Yes, ࠷ॳͷઃܭ͸೉͍͠ɻઃܭతͳ೉͠͞Λ৐Γӽ͑ Ε͹࣮૷͸೉͘͠ͳ͍ɻ͞Βʹ࠷ۙ͸Next.jsͱ͔Nuxt.jsͱ͔ग़ͯ Δ͔Βঃʑʹ೉͘͠ͳ͘ͳ͖ͬͯͯΔ͔΋ɻ

Slide 62

Slide 62 text

Thank you