Slide 1

Slide 1 text

1SPHSFTTJWF )ZESBUJPO !QJSPTJLJDL ʢ8FEʣ 3FBDUษڧձ!෱ԬWPM

Slide 2

Slide 2 text

w !QJSPTJLJDL w αΠϘ΢ζגࣜձࣾ
 ϑϩϯτΤϯυΤΩεύʔτνʔϜ w స৬͠·ͨ͠!
 ෱ԬͷΤϯδχΞ͸·ͩҰਓͰ͕͢
 ͨͷ͍͠৬৔Ͱ͢ w ෱ԬͰ΋࠾༻ͯ͠·͢ ࣗݾ঺հ

Slide 3

Slide 3 text

࿩͢͜ͱ w )ZESBUJPOͷ͓͞Β͍ w 1SPHSFTTJWF)ZESBUJPOʹ͍ͭͯ

Slide 4

Slide 4 text

)ZESBUJPOͷ͓͞Β͍

Slide 5

Slide 5 text

)ZESBUJPOͱ͸ʁ w 4FSWFS4JEF3FOEFSJOHʢҎԼɺ443ʣʹΑͬͯ
 ඳը͞ΕͨίϯςϯπΛɺ w $MJFOU4JEF3FOEFSJOHʢҎԼɺ$43ʣͰ࢖͍ճ͢͜ͱ

Slide 6

Slide 6 text

$43POMZ w ίϯϙʔωϯτͷπϦʔ͔Β%0.Λੜ੒ɺඳը w Πϕϯτϋϯυϥʔͷઃఆ // client.js import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render( , document.getElementById('root') );

Slide 7

Slide 7 text

443)ZESBUJPO w αʔόʔαΠυ w ίϯϙʔωϯτπϦʔΛ)5.-ͷจࣈྻʹม׵͠ɺϨεϙϯε͢Δ • ReactDOMServer.{renderToString|renderToNodeStream} // server.js const ReactDOMServer = require('react-dom/server'); …省略 app.get('/', (req, res) => { const html = ReactDOMServer.renderToNodeStream( ); html.pipe(res); });

Slide 8

Slide 8 text

443)ZESBUJPO w ΫϥΠΞϯταΠυ w 443͕ฦ͢)5.-Ͱ%0.͕ߏஙɾඳըࡁΈ w ΠϕϯτϋϯυϥʔͷઃఆͷΈΛߦ͏ w 3FBDU%0.SFOEFSͰ͸ͳ͘ɺ3FBDU%0.IZESBUFΛ࢖͏ // client.js import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.hydrate( , document.getElementById('root') );

Slide 9

Slide 9 text

$41POMZ )551(&5 +4ͷμ΢ϯϩʔυ +4ͷ࣮ߦ '$1 +4͕࣮ߦ͞ΕΔ·Ͱը໘͕ਅͬന '$1'JSTU$POUFOUGVM1BJOUɺ ϖʔδભҠ͔Β࠷ॳͷίϯςϯπඳը·Ͱͷ࣌ؒ

Slide 10

Slide 10 text

443)ZESBUJPO )551(&5 +4ͷμ΢ϯϩʔυ +4ͷ࣮ߦ '$1 '$1 '$1͕଎͘ͳΔ 443Ͱ ඳը͞ΕΔ

Slide 11

Slide 11 text

͜͜·Ͱͷ·ͱΊ w )ZESBUJPO͸443ͷ݁ՌΛ$43Ͱ࢖͍ճ͢͜ͱΛݴ͏ w 443ʴ)ZESBUJPOʹΑͬͯ'$1͕଎͘ͳΔ w αʔόʔαΠυͰ͸
 3FBDU%0.4FSWFSSFOEFS5P4USJOH͔ 3FBDU%0.4FSWFSSFOEFS5P/PEF4USFBNΛ࢖͏ w ΫϥΠΞϯταΠυͰ͸
 3FBDU%0.SFOEFSͰ͸ͳ͘3FBDU%0.IZESBUFΛ࢖͏

Slide 12

Slide 12 text

1SPHSFTTJWF )ZESBUJPO ʹ͍ͭͯ

Slide 13

Slide 13 text

)ZESBUJPOͷ໰୊఺ w '$1͸଎͘ͳΔ͕55*͸଎͘ͳΒͳ͍ w 55*5JNF5P*OUFSBDUJWF w ϖʔδ͕ΠϯλϥΫςΟϒʢૢ࡞Մೳʣʹ
 ͳΔ·Ͱͷ࣌ؒ w ඳը͞Εͯ΋ૢ࡞ՄೳʹͳΔͷ͸ɺ+4͕࣮ߦ͞Εͨޙ

Slide 14

Slide 14 text

$41POMZ )551(&5 +4ͷμ΢ϯϩʔυ +4ͷ࣮ߦ '$1 55*

Slide 15

Slide 15 text

443)ZESBUJPO )551(&5 +4ͷμ΢ϯϩʔυ +4ͷ࣮ߦ '$1 55*

Slide 16

Slide 16 text

1SPHSFTTJWF)ZESBUJPO w )ZESBUJPOΛஈ֊తʹߦ͏͜ͱͰ55*Λ୹ॖ͢Δ w (PPHMF*0Ͱ঺հ͞ΕͨςΫχοΫ w 3FOEFSJOHPOUIF8FC
 1FSGPSNBODF*NQMJDBUJPOTPG"QQMJDBUJPO"SDIJUFDUVSF
 IUUQTZPVUVCFL"7GV630H

Slide 17

Slide 17 text

443)ZESBUJPO )551(&5 +4ͷ%- +4ͷ࣮ߦ '$1 55* Ұؾʹ)ZESBUJPO

Slide 18

Slide 18 text

1SPHSFTTJWF)ZESBUJPO +4ͷ࣮ߦ 55* ඞཁͳ෼͚ͩ)ZESBUJPO )551(&5 +4ͷ%- '$1 +4ͷ࣮ߦ ࢒Γͷ)ZESBUJPO Ұؾʹ΍ΔΑΓ ଎͘ͳΔ ඞཁʹͳͬͨΒ )ZESBUJPO͢Δ ɾɾɾ

Slide 19

Slide 19 text

σϞ w (PPHMF͕σϞΛެ։͍ͯ͠Δ w IUUQTHJUIVCDPN(PPHMF$ISPNF-BCTQSPHSFTTJWF SFOEFSJOHGSBNFXPSLTTBNQMFT w ϑΝʔετϏϡʔͷޙʹ݅ͷϦετ͕͋Δϖʔδ w Ϧετ෦෼͸࠷ॳͷ)ZESBUJPOͷର৅֎ w Ϧετ෦෼͸ը໘಺ʹೖͬͨλΠϛϯάͰ
 )ZESBUJPO͞ΕΔ

Slide 20

Slide 20 text

ϑΝʔετϏϡʔ ࠷ॳʹ)ZESBUJPO͞ΕΔ Ϧετ෦෼ ը໘಺ʹೖͬͨΒ)ZESBUJPO͞ΕΔ

Slide 21

Slide 21 text

"VEJUTͰൺֱ 1)ͳ͠ 1)͋Γ 55*͕ඵߴ଎ʹ

Slide 22

Slide 22 text

αϯϓϧͷιʔείʔυΛ ಡΉ w BQQKT w ϧʔτίϯϙʔωϯτ͕ఆٛ͞Ε͍ͯΔ w TUSFBNKTʢ˞ࠓճ͸ಡ·ͳ͍ʣ w Ϧετ෦෼ͷ4USFBNίϯϙʔωϯτ͕ఆٛ͞Ε͍ͯΔ w IZESBUPSKT w 1SPHSFTTJWF)ZESBUJPOΛ࣮ߦ͢Δίϯϙʔωϯτ

Slide 23

Slide 23 text

// app.js … let load = () => import('./stream'); let Hydrator = ClientHydrator; if (typeof window === 'undefined') { Hydrator = ServerHydrator; load = () => require('./stream'); } export default function App() { return (
); } BQQKT ϧʔτίϯϙʔωϯτʢ"QQʣ

Slide 24

Slide 24 text

// app.js … let load = () => import('./stream'); let Hydrator = ClientHydrator; if (typeof window === 'undefined') { Hydrator = ServerHydrator; load = () => require('./stream'); } export default function App() { return (
); } $43Ͱ͸%ZOBNJD*NQPSUͰ 4USFBNίϯϙʔωϯτΛಡΈࠐΉ 4USFBNίϯϙʔωϯτ͸ #VOEMF͕෼͔Εɺ ಈతʹϒϥ΢βʹϩʔυ͞ΕΔ

Slide 25

Slide 25 text

// app.js … let load = () => import('./stream'); let Hydrator = ClientHydrator; if (typeof window === 'undefined') { Hydrator = ServerHydrator; load = () => require('./stream'); } export default function App() { return (
); } 443࣌͸੩తʹ 4USFBNίϯϙʔωϯτΛಡΈࠐΉ

Slide 26

Slide 26 text

// app.js … let load = () => import('./stream'); let Hydrator = ClientHydrator; if (typeof window === 'undefined') { Hydrator = ServerHydrator; load = () => require('./stream'); } export default function App() { return (
); } )ZESBUPSίϯϙʔωϯτ͕ 1SPHSFTTJWF)ZESBUJPOΛ࣮ߦ͢Δ QSPQTMPBE͕ฦ͢ίϯϙʔωϯτ͸ ஗Ԇͯ͠)ZESBUJPO͞ΕΔ

Slide 27

Slide 27 text

// hydrator.js … export class Hydrator extends React.Component { shouldComponentUpdate() { return false; } componentDidMount() { new IntersectionObserver(async ([entry], obs) => { if (!entry.isIntersecting) return; obs.unobserve(this.root); const { load, ...props } = this.props; const Child = interopDefault(await load()); ReactDOM.hydrate(, this.root); }).observe(this.root); } render() { return ( this.root = c} dangerouslySetInnerHTML={{ __html: '' }} suppressHydrationWarning /> ); } } IZESBUPSKT )ZESBUPS$MJFOU)ZESBUPS

Slide 28

Slide 28 text

// hydrator.js … export class Hydrator extends React.Component { shouldComponentUpdate() { return false; } componentDidMount() { new IntersectionObserver(async ([entry], obs) => { if (!entry.isIntersecting) return; obs.unobserve(this.root); const { load, ...props } = this.props; const Child = interopDefault(await load()); ReactDOM.hydrate(, this.root); }).observe(this.root); } render() { return ( this.root = c} dangerouslySetInnerHTML={{ __html: '' }} suppressHydrationWarning /> ); } } w TIPVME$PNQPOFOU6QEBUFͰ
 ৗʹGBMTFΛฦ͍ͯ͠ΔͷͰ
 Ξοϓσʔτ͞Εͳ͍

Slide 29

Slide 29 text

// hydrator.js … export class Hydrator extends React.Component { shouldComponentUpdate() { return false; } componentDidMount() { new IntersectionObserver(async ([entry], obs) => { if (!entry.isIntersecting) return; obs.unobserve(this.root); const { load, ...props } = this.props; const Child = interopDefault(await load()); ReactDOM.hydrate(, this.root); }).observe(this.root); } render() { return ( this.root = c} dangerouslySetInnerHTML={{ __html: '' }} suppressHydrationWarning /> ); } } w ۭͷཁૉΛग़ྗɺ
 ཁૉͷSFGΛऔಘ w EBOHFSPVTMZ4FU*OOFS)5.-Ͱ
 ۭจࣈΛઃఆ͢Δͱɺ
 )ZESBUJPOΛᷖճ͢Δ

Slide 30

Slide 30 text

// hydrator.js … export class Hydrator extends React.Component { shouldComponentUpdate() { return false; } componentDidMount() { new IntersectionObserver(async ([entry], obs) => { if (!entry.isIntersecting) return; obs.unobserve(this.root); const { load, ...props } = this.props; const Child = interopDefault(await load()); ReactDOM.hydrate(, this.root); }).observe(this.root); } render() { return ( this.root = c} dangerouslySetInnerHTML={{ __html: '' }} suppressHydrationWarning /> ); } } w *OUFSTFDUJPO0CTFSWFSͰ
 ཁૉͷεΫϩʔϧҐஔΛ؂ࢹ w ཁૉ͕ը໘಺ʹೖͬͨΒɺ
 )ZESBUJPOΛ࣮ߦ

Slide 31

Slide 31 text

w αʔόʔαΠυ͸ී௨ʹ443Λ΍Δ w )ZESBUPSίϯϙʔωϯτͷ഑Լ͸
 ࠷ॳͷ)ZESBUJPOΛᷖճ͢Δ w EBOHFSPVTMZ4FU*OOFS)5.-ʹۭจࣈΛ౉͢ w )ZESBUPSίϯϙʔωϯτͷ഑Լ͕
 ը໘಺ʹೖͬͨΒͦͷ෦෼ͷ)ZESBUJPOΛ࣮ߦ w *OUFSTFDUJPO0CTFSWFSͰ؂ࢹ͠ɺ
 3FBDU%0.IZESBUFΛ࣮ߦ

Slide 32

Slide 32 text

·ͱΊ

Slide 33

Slide 33 text

w 1SPHSFTTJWF)ZESBUJPO͸
 ஈ֊తʹ)ZESBUJPO͢Δ͜ͱͰ55*Λ୹ॖ͢Δ w ݱঢ়͸)BDLZͳ࣮૷͕ͩɺެࣜʹରԠ༧ఆ͕͋Δ w "OHVMBSɺ7VFͰ΋Ͱ͖ΔʢΒ͍͠ʣ

Slide 34

Slide 34 text

1SPHSFTTJWF)ZESBUJPO͸ ಋೖ͢΂͖͔ʁ w ಋೖʹϦεΫ͕΄΅ͳ͍ w )ZESBUPSίϯϙʔωϯτΛऔΓআ͚ͩ͘Ͱݩʹ໭ͤΔ w ݱঢ়͸ϋοΫͬΆ͍࣮૷ɻόʔδϣϯΞοϓ࣌ʹ஫ҙ͕ඞཁ͔΋ w 55*͕ಛผ஗͍৔ॴͰಋೖ͢Δͷ͕Αͦ͞͏ w 55*͕଎͍৔ॴͰ͸ޮՌ͕ബ͍ͷͰɺ
 શϖʔδͰಋೖ͢΂͖͔͸ඍົ w "VEJUTͰܭଌ͠·͠ΐ͏

Slide 35

Slide 35 text

w (PPHMF*0ͷ8FCΛ·ͱΊΔձ
 IUUQTNFOUBJDPKTDPOOQBTTDPNFWFOU w ʢਫʣ w ·ۭ͍ͩͯ·͢ͷͰɺͥͻʙ

Slide 36

Slide 36 text

͋Γ͕ͱ͏ ͍͟͝·ͨ͠