Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Vue.js 2.0 Server Side Rendering

kazupon
November 13, 2016

Vue.js 2.0 Server Side Rendering

Nodefest 2016 Nov 13

kazupon

November 13, 2016
Tweet

More Decks by kazupon

Other Decks in Programming

Transcript

  1. Vue.js 2.0 αʔόαΠυϨϯμϦϯά ౦ژNodeֶԂࡇ2016 2016-11-13 @kazupon

  2. ࣗݾ঺հ

  3. Vue.js Core Team member https://github.com/kazupon

  4. vuejs-jp ༗ࢤͰٕज़ධ࿦༷ࣾʹͯ Web هࣄ࿈ࡌத http://gihyo.jp/dev/serial/01/vuejs

  5. We are building Open Innovation Platform!! https://cuusoo.com

  6. Vue.js ͱ͸ʁ

  7. ࡞ऀ Evan You ※ ࡞ऀͷΠϯλϏϡʔهࣄ: Between the Wires | Evan

    You
 https://betweenthewires.org/between-the-wires-evan-you-cb56660bc8a4#.6b0vzpgzw ※ ࡞ऀͷαΠτ
 http://evanyou.me
  8. ϓϩάϨογϒϑϨʔϜϫʔΫ

  9. ※ CC BY Evan You
 https://docs.google.com/presentation/d/1WnYsxRMiNEArT3xz7xXHdKeH1C-jT92VxmptghJb5Es/edit#slide=id.p ※ ԼهURL࿈ࡌهࣄ
 http://gihyo.jp/dev/serial/01/vuejs/0001?page=1 vue-router

    vuex vue-loader vueify vue-cli কདྷ ఏڙ༧ఆ vue.js ຊମ
  10. • 2016೥10݄1೔(೔ຊ࣌ؒ)
 ίʔυωʔϜ: Ghost in the Shell
 ϦϦʔεʂ ࠷৽όʔδϣϯ 2.0

    2017 2014 2015 2016 spawn 0.6 0.8 0.9 0.10 0.11 0.12 1.0 2.0 2013 ※ Πϥετஶ࡞ऀ: @hashedrock ࢯ https://twitter.com/hashedrock/status/782069763358924800 Animatrix Blade
 Runner Cowboy
 Bebop Dragon
 Ball Evangelion ghost in the shell
  11. 2.0 Ͱͷେ͖͍มߋ

  12. ϨϯμϦϯάγεςϜ͕࡮৽ʂ • Virtual DOM ΞʔΩςΫνϟΛ࠾༻ • Evan You ࢯʹΑΔϑϧεΫϥον࣮૷ •

    2िؒͨΒͣͰpre-alphaόʔδϣϯΛ࣮૷
  13. Virtual DOM ʹΑΔޮೳ

  14. ϨϯμϦϯάͷߴ଎Խ ※ The Vue Point: Vue 2.0 is Here (Vue.js

    ެࣜϒϩά)
 https://medium.com/the-vue-point/vue-2-0-is-here-ef1f26acf4b8#.v9xl2x8f7
  15. αʔόαΠυϨϯμϦϯά Request Response Client Server render

  16. ॊೈͳϨϯμϦϯάखஈ • એݴతϨϯμϦϯά • ςϯϓϨʔτ • ໋ྩతϨϯμϦϯά • Ծ૝ϊʔυΛར༻ͨ͠ JavaScript

    ࣮૷ • hyperscript / JSX
  17. ΫϩεϓϥοτϑΥʔϜରԠ • ϚϧνϞόΠϧσόΠε޲͚ͷϑϨʔϜϫʔΫ ※ weex
 https://alibaba.github.io/weex/

  18. ΞδΣϯμ

  19. ࠓ೔࿩͢͜ͱ • ϨϯμϦϯάγεςϜ • αʔόαΠυϨϯμϦϯά

  20. ϨϯμϦϯάγεςϜ

  21. Vue ͷΑ͋͘ΔҰൠతͳίʔυ <html> <head> ... <script src="./vue.js"></script> </head> <body>
 ...

    <div id="app"></div>
 <script> new Vue({ template: `<div> <p>message: {{msg}}</p> </div>`, data: { msg: 'hi evan!!' } }).$mount('#app') </script>
 ... </body> </html>
  22. ಺෦Ͱ͸৭ʑͱΰχϣΰχϣ͢Δ ॳظϨϯμϦϯά׬ྃ ࠶ϨϯμϦϯά

  23. ҰൠతͳϨϯμϦϯάͷྲྀΕͰ ಺෦ʹ͍ͭͯݟ͍͖ͯ·͠ΐ͏ʂ

  24. ҰൠతͳϨϯμϦϯάͷྲྀΕ optimize diff + patch compile generate rendering track dependencies

    AST Optimized AST Virtual DOM
  25. ίϯύΠϧ

  26. ςϯϓϨʔτΛ AST ʹม׵ • ςϯϓϨʔτύʔαΛར༻ͯ͠AST (Abstract Syntax Tree) ʹม׵ <div

    id="app"> <h1>title</h1> <p class="msg"> msg: {{msg}} </p> </div> Template { tag: 'div', type: 1, children: [{ tag: 'h1', type: 1, children: [{ type: 3, text: 'title', … }], … }, { tag: 'p', type: 1, children: [{ type: 2, text: 'msg: {{msg}}', … }], … }] } compile AST
  27. ςϯϓϨʔτύʔα • ςϯϓϨʔτύʔα͸ɺJohn Resig ࢯ੡ͷ΋ͷΛ fork ͠ ͯ Vue ޲͚ʹಠࣗʹΧελϚΠζ

    ※ ςϯϓϨʔτύʔα
 https://github.com/vuejs/vue/blob/dev/src/compiler/parser/html-parser.js ES2015 Ͱ re-write & ࠷దԽ
  28. ࠷దԽ

  29. Ұൠతͳ Virtual DOM New Virtual Node Tree Old Virtual Node

    Tree diff + patch Ծ૝ϊʔυπϦʔͷ diff ࢉग़ίετ͕͔͔Δ
  30. • Virtual DOM ʹΑΔϨϯμϦϯάͷύϑΥʔϚϯεΛΑ ͘͢ΔͨΊʹɺVue Ͱ͸ AST ʹରͯ͠ҎԼͷ̎ஈ֊ͷॲ ཧΛͯ͠࠷దԽ͢Δ
 


    1. ੩తͳϊʔυͷݕग़
 2. ੩తͳϊʔυπϦʔͷݕग़ AST ʹର͢Δ࠷దԽॲཧ
  31. 1. ੩తͳϊʔυͷݕग़ • ҎԼͷΑ͏ͳςϯϓϨʔτͷέʔεͷ৔߹͸ <div id="app"> <div class="header">title: {{title}}</div> <ul

    style="list-style-type: none" class="menu"> <li style="margin: 0" :class="{ even: isEven(index), odd: isOdd(index) }" v-for="(item, index) in items"> menu{{index}}: {{item}} </li> </ul> <div class="content"> <p>This is content</p> </div> </div> divɺpɺͦͯ͠ text ཁૉΛ ੩తͳϊʔυͱͯ͠ݕग़
  32. • ݕग़͞Εͨϊʔυ͸ɺAST ʹ static = true ͱͯ͠ϚʔΩ ϯά͞ΕΔ 1. ੩తͳϊʔυͷݕग़

    { tag: 'div', children: [{ tag: 'div', … }, { tag: 'ul', children: […], … }, { tag: 'div', static: true, children: [{ tag: 'p', static: true, children: [{ static: true, text: 'This is content', … }] }], … }] }
  33. 2. ੩తͳϊʔυπϦʔͷݕग़ • ੩తͳϊʔυΛࢠͱͯ࣋ͭ͠ϧʔτ(root)ͱͳΔཁૉ͕ ͋Δ͔Ͳ͏͔νΣοΫ͢Δ <div id="app"> <div class="header">title: {{title}}</div>

    <ul style="list-style-type: none" class="menu"> <li style="margin: 0" :class="{ even: isEven(index), odd: isOdd(index) }" v-for="(item, index) in items"> menu{{index}}: {{item}} </li> </ul> <div class="content"> <p>This is content</p> </div> </div> ͜ͷέʔεͰ͸ɺ͜ͷ div ཁૉ͕ ੩తͳϊʔυπϦʔͱͯ͠ݕग़
  34. 2. ੩తͳϊʔυπϦʔͷݕग़ • ݕग़͢ΔͱɺAST ʹ staticRoot = true ͱͯ͠ϚʔΩϯά͢Δ {

    tag: 'div', children: [ { tag: 'div', … }, { tag: 'ul', children: […], … }, { tag: 'div', static: true, staticRoot: true, children: [ { tag: 'p', static: true, children: [{ text: 'This is content', static: true, … }], … } ], … } ] }
  35. ϨϯμϦϯάؔ਺ͷੜ੒

  36. AST ͔ΒϨϯμϦϯάؔ਺Λੜ੒ • ҎԼͷؔ਺Λੜ੒͢Δ • render ؔ਺ • staticRenderFns ؔ਺܊

    (഑ྻ) • ͜ΕΒؔ਺͸ɺVue Πϯελϯ εͷ $options ʹ֨ೲ͞ΕΔ Optimized AST
  37. render ؔ਺ • Ծ૝ϊʔυπϦʔΛฦؔ͢਺
 (e.g. ࠷దԽͰઆ໌ͨ͠ASTΛrenderؔ਺Խͨ͠΋ͷ) function anonymous () {

    with (this) { return _h('div', { attrs: { 'id': 'app' } }, [ _h('div', { staticClass: 'header'}, ['title: 'ɹ+ɹ_s(title)]), _h('ul', { staticClass: 'menu', attrs: { style: 'list-style-type: none' } }, [_l((items), function (item, index) { return _h('li', { ɹɹɹɹɹɹɹɹɹɹkey: item.id, class: { even: isEven(index), odd: isOdd(index) }, attrs: { style:'margin: 0' } }, ['menu' + _s(index) + ': ' + _s(item.name)]) })] ), _m(0) ]) } ࠷దԽʹΑΓݕग़͞Εͨ੩తͳϊʔυπϦʔͷ෦෼͸ɺ ಺෦ϝιουʹϚοϐϯά
  38. staticRenderFns ؔ਺܊ • ࠷దԽʹΑΓ AST Ͱݕग़ͨ͠੩తͳϊʔυπϦʔ͸ɺ Ծ૝ϊʔυπϦʔͱͯ͠ฦ͢Α͏ʹੜ੒ͨؔ͠਺Λ഑ྻ ʹ֨ೲ͢Δ [ function

    anonymous () { with (this) { return _h('div', { staticClass: 'content' }, [ _h('p', ['This is content']) ]) }} ]
  39. ϨϯμϦϯά

  40. ϦΞΫςΟϒγεςϜʹΑΔϨϯμϦϯά diff + patch create call Virtual Node Tree notify

  41. Watcher ʹΑΔσʔλมߋͷ؂ࢹ • σʔλґଘؔ܎Λ௥੻͠ɺσʔλมߋΛ؂ࢹ͢Δ • σʔλมߋݕग़ͷ౎౓ɺ Watcher ͸಺෦ͷ _render ϝ

    ιουΛݺͼग़ͯ͠࠶ϨϯμϦϯά const Component = { props: ['msg'], data () { return { title: 'hello', items: […] } }, … } msg data/props Watcher title items 0 x … Collect Dependencies
  42. Ծ૝ϊʔυπϦʔͷੜ੒ • render ؔ਺ͱ staticRenderFns ؔ਺܊ͰԾ૝ϊʔυπϦʔ Λੜ੒ function anonymous ()

    { with (this) { return _h('div', { attrs: { 'id': 'app' } }, [ _h('div', { staticClass: 'header'}, ['title: 'ɹ+ɹ_s(title)]), _h('ul', { staticClass: 'menu', attrs: { style: 'list-style-type: none' } }, [_l((items), function (item, index) { return _h('li', { ɹɹɹɹɹɹɹɹɹɹkey: item.id, class: { even: isEven(index), odd: isOdd(index) }, attrs: { style: 'margin: 0' } }, ['menu” + _s(index) + ": “ + _s(item.name)]) })] ), _m(0) ]) } [ function anonymous () { with (this) { return _h('div', { staticClass: 'content' }, [ _h('p', ['This is content']) ]) }} ] staticRenderFns render
  43. Ծ૝ϊʔυπϦʔͷΩϟγϡԽͱϚʔΩϯά • staticRenderFns ͷ࣮ߦ݁ՌͰಘΒΕΔ੩తͳԾ૝ϊʔυ πϦʔ͸ɺ࠷ॳͷϨϯμϦϯάͷࡍʹ͜ΕΒ݁ՌΛ Vue Πϯελϯε಺෦ʹΩϟογϡ͢Δ • ͜ͷ࣌ɺԾ૝ϊʔυπϦʔʹ isStatic

    = true ͰϚʔΩϯ ά͢Δ͜ͱͰɺޙͷ Virtual DOM ͷ diff ʹ͓͍ͯεΩο ϓ͞ΕΔ • ࠶ϨϯμϦϯά࣌ʹ͸ɺΩϟογϡԽ͞Εͨ΋ͷΛར༻
  44. Vue ͷ Virtual DOM • Virtual DOM ͸ snabbdom Λ

    fork ͯ͠ಠࣗʹΧελϚΠ ζͨ͠΋ͷ
 https://github.com/snabbdom/snabbdom
  45. Virtual DOM ͷ diff / patch • diff / patch

    ͸جຊ snabbdom ϕʔεͰɺVue ͷ࠷దԽॲ ཧʹΑͬͯ diff ΛεΩοϓ͢Δ͜ͱͰɺDOM Λੜ੒͢Δ ·ͰॲཧίετΛ࡟ݮ https://github.com/vuejs/vue/blob/dev/src/core/vdom/patch.js
  46. Ծ૝ϊʔυπϦʔͷੜ੒͔Β Virtual DOM ʹΑΔॲཧ·Ͱͷ Πϝʔδ

  47. ॳظͷϨϯμϦϯά return caching & marking create diff + patch skip

    diff of the marked tree
  48. ߋ৽࣌ͷ࠶ϨϯμϦϯά return create diff + patch skip diff of the

    marked tree
  49. ίϯϙʔωϯτπϦʔ ͷ ϨϯμϦϯά

  50. • ֤ίϯϙʔωϯτຖʹ Watcher Λհͯ͠τοϓμ΢ϯత ʹϨϯμϦϯά Ұ൪τοϓ͔Βࢠʹ޲͔ͬͯϨϯμϦϯά Watcher track dependencies component

    Root (new Vue)
  51. • ίϯϙʔωϯτ಺ͷ data/props ͕ɺଞʹґଘ͕ͳ͘ɺ ͦͷίϯϙʔωϯτ಺ͷΈͳΒɺͦͷίϯϙʔωϯτͩ ͚࠶ϨϯμϦϯά ίϯϙʔωϯτ಺ʹดͨ͡σʔλͷมߋݕग़ Root (new Vue)

  52. • ίϯϙʔωϯτ಺ͷ data/props ͕ɺଞͷࢠίϯϙʔω ϯτʹόέπϦϨʔ͍ͯ͠Δ৔߹͸ɺόέπϦϨʔઌͷ ࢠίϯϙʔωϯτ΋࠶ϨϯμϦϯά σʔλͷ୯ํ޲όΠϯσΟϯά pass props Root

    (new Vue)
  53. • ࢠίϯϙʔωϯτ͕਌ίϯϙʔωϯτͱv-modelͰ૒ํ ޲σʔλόΠϯσΟϯά͍ͯ͠Δ৔߹͸ɺ਌ʹσʔλม ߋΛ௨஌ͨ͠৔߹͸ɺࢠ΋࠶ϨϯμϦϯά͢Δ v-modelʹΑΔ૒ํ޲όΠϯσΟϯά pass props emit events Root

    (new Vue)
  54. ଞͷ ϨϯμϦϯάγεςϜ ͱͷൺֱ

  55. Demystifying Frontend Framework Performance • Nodric.js 2016 Ͱൃදͨ͠ Evan You

    ࢯͷ্هλΠτϧͷࢿ ྉ͕Α͘·ͱ·͍ͬͯΔͷͰɺҰݟ͢Δ͜ͱΛ͓קΊ͢ Δ • εϥΠυ
 https://docs.google.com/presentation/d/ 1Ju5NryLLI-2aXm_XwsdF5rU0QpOpeyVW9F8JeeSuj-k/ edit#slide=id.p • ϏσΦ
 https://www.youtube.com/watch?v=Ag-1wmHWwS4
  56. ͞ΒͳΔ࠷దԽʹ޲͚ͯ

  57. ࠷దԽ߲໨ • ςϯϓϨʔτͷࣄલίϯύΠϧ + ϥϯλΠϜ • v-for ʹΑΔϦετϨϯμϦϯά࣌ʹ͓͚Δ key ଐੑ

    • render ؔ਺ʹΑΔύϑΥʔϚϯενϡʔχϯά࣮૷ • ؔ਺ܕίϯϙʔωϯτ (functional component)
  58. αʔόαΠυϨϯμϦϯά

  59. αʔόαΠυϨϯμϦϯάͷॏཁੑ • γϯάϧϖʔδΞϓϦέʔγϣϯʹΑΓϢʔβʔʹ৺஍ ྑ͍UXΛఏڙͰ͖ΔΑ͏ʹͳͬͨ • ͕ɺҎԼͷ໰୊఺͕͋Δ • SEOରࡦ • ॳظදࣔͷϩʔσΟϯά࣌ؒ

  60. ैདྷͷVueͰ͸೉͔ͬͨ͠ • Vue 2.0 ҎલͷόʔδϣϯͰ͸ɺυΩϡϝϯτϑϥάϝϯ τʹΑΔੜDOMϕʔεʹΑΔϨϯμϦϯάͷͨΊɺίΞ ଆͰ͸αϙʔτ͍ͯ͠ͳ͔ͬͨ • ରԠ͢Δʹ͸ɺαʔυϕϯμͷϨϯμϥΛར༻͢Δ͔ɺ ಠࣗʹରԠ͢Δඞཁ͕͋ͬͨ

    • ͞ΒʹɺϋΠυϨʔγϣϯͷ࢓૊ΈɺΫϥΠΞϯταΠ υͷϥΠϒϥϦͷαʔόαΠυରԠͳͲɺશ෦ಠࣗʹର Ԡ͢Δඞཁ͕͋ͬͨ
  61. Vue 2.0 Ͱ͸؀ڥ͕େ͖͘վળ • Virtual DOM ʹΑΓந৅Խ͞ΕͨϨϯμϦϯά • ϋΠυϨʔγϣϯͷ࢓૊Έ •

    ϢχόʔαϧରԠ͞Εͨެࣜʹఏڙ͢ΔϥΠϒϥϦ • Node.js ޲͚ʹϨϯμϥ • ίϯςΩετʹΑΔႈ౳ੑΛอূ͢ΔϨϯμϦϯά • αʔό޲͚ʹ࠷దԽ͞ΕͨϞδϡʔϧͷόϯυϦϯά
  62. • Vue 2.0 Ҏ߱Ͱ͸ɺҎԼͷެࣜϥΠϒϥϦͱόϯυϦϯ άπʔϧͰɺαʔόαΠυϨϯμϦϯάΛ༰қʹ࣮ݱ͢ Δ͜ͱ͕Ͱ͖Δ ੔ͬͨαʔόαΠυϨϯμϦϯά؀ڥ vue vuex vue-router

    vue-server-renderer Vue library stack + and other …
  63. Vue 2.0 ʹ͓͚Δ αʔόαΠυϨϯμϦϯά ͷྲྀΕʹ͍ͭͯݟ͍͖ͯ·͠ΐ͏ʂ

  64. Client Server αʔόଆͰ͸ɺVueͰ࡞ΒΕͨ ΞϓϦέʔγϣϯίʔυ͕ αʔόଆͰ΋ಈ࡞͢ΔΑ͏όϯ υϧԽ͞Εͨ΋ͷ͕ಡΈࠐ·Ε ͯಈ࡞ ίϯϙʔωϯτΛαʔόଆ ͰϨϯμϦϯά͢ΔͨΊͷ Ϩϯμϥ΋ΠϯελϯεԽ

  65. Client Server ϦΫΤετ GET /:user_id/profile ϢʔβʔʹΑΔΞΫηε ɾɾɾ ϦΫΤετຖʹ αϯυϘοΫεΛ࡞੒ͯ͠ ίϯςΩετΛࢦఆͯ͠

    ΤϯτϦϙΠϯτͷ Vue Λ࣮ߦͤ͞Δ
  66. Client Server route ʹରԠ͢Δ ίϯϙʔωϯτΛ ಈ࡞ͤ͞ɺσʔλ ΛϑΣον ɾɾɾ ΫϥΠΞϯτʹ౉͢ॳظঢ়ଶΛJSONͱ͠ ͯຒΊࠐΉΑ͏ʹ

    HTMLϨϯμϦϯάͯ͠ϨεϙϯεΛฦ͢
  67. Client Server Ϩεϙϯε Ϛ΢ϯτ&ϋΠυϨʔτ ΫϥΠΞϯτ͸αʔό͔ΒϨϯμϦϯά͞Ε ͨHTMLͱΫϥΠΞϯτ޲͚ʹόϯυϧԽ͞ ΕͨΞϓϦέʔγϣϯίʔυ͕഑৴͞ΕΔ ϒϥ΢βଆͰHTMLΛϩʔυͨ͠ ޙɺΤϯτϦϙΠϯτͱͳΔVueΛ ಈ࡞ͤ͞ɺϚ΢ϯτ&ϋΠυϨʔτ

    ʹΑ࣮ͬͯࡍʹ಺༰Λදࣔ͢Δ
  68. Client Server ޙ͸ɺΫϥΠΞϯτଆͰ ϧʔςΟϯάΛߦ͍ɺ ඞཁʹԠͯ͡σʔλΛϑΣονͯ͠ ϨϯμϦϯά͢Δ

  69. αʔόαΠυϨϯμϦϯάΛߏ੒͢Δ4ཁૉ • 1. Ϩϯμϥ • 2. ϋΠυϨʔγϣϯ • 3. ίϯςΩετ

    • 4. όϯυϦϯά
  70. 1. Ϩϯμϥ

  71. ఏڙ͢ΔϨϯμϥ • Vue ΞϓϦέʔγϣϯΛαʔόαΠυͰϨϯμϦϯά͢ ΔͨΊͷ Node.js ؀ڥͰಈ࡞͢ΔϨϯμϦϯάϞδϡʔ ϧ • Ϩϯμϥ͸ɺࢦఆ͞Εͨ

    Vue ΞϓϦέʔγϣϯͷrender ؔ਺ʹΑͬͯऔಘͨ͠Ծ૝ϊʔυπϦʔΛ walk ͯ͠ HTML จࣈྻͱͯ͠ϨϯμϦϯά
  72. جຊతͳ࢖͍ํ • NPMͰΠϯετʔϧ
 $ npm install vue-server-renderer • ϨϯμϥΛ࡞੒ͯ͠ɺrenderToString ͰϨϯμϦϯά

    const Vue = require('vue') const renderer = require('vue-server-renderer').createRenderer() const vm = new Vue({ render (h) { return h('div', 'hello') } }) renderer.renderToString(vm, (err, html) => { console.log(html) // -> <div server-rendered="true">hello</div> })
  73. Stream ʹΑΔϨϯμϦϯά • Node.js ͷ Stream API ΋αϙʔτɻrenderToStream Ͱ stream

    Λ࡞੒ͯ͠ɺstream ΠϯλʔϑΣΠεʹΑͬͯϊ ϯϒϩοΩϯάͳϨϯμϦϯά͕Մೳ app.get('/', (req, res) => { const vm = new App({ url: req.url }) const stream = renderer.renderToStream(vm) res.write(`<!DOCTYPE html><html><head><title>...</title></head><body>`) stream.on('data', chunk => { res.write(chunk) }) stream.on('end', () => { res.end('</body></html>') }) })
  74. ΩϟγϡʹΑΔߴ଎Խ • Φϓγϣϯʹ cache ΦϒδΣΫτΛࢦఆ͢Δ͜ͱͰɺί ϯϙʔωϯτͷඳը݁ՌΛΩϟογϯά͢Δ͜ͱʹΑ Γɺ͞ΒͳΔύϑΥʔϚϯεΛ޲্͕Մೳ const LRU =

    require('lru-cache') const renderer = createRenderer({ cache: LRU({ max: 10000 }) })
  75. Ωϟγϡʹ͓͚ΔඞࢸΠϯλʔϑΣΠε • Φϓγϣϯʹ ࢦఆ͢Δ cache ΦϒδΣΫτ͸ɺҎԼͷ ΠϯλʔϑΣΠεΛ࣮૷͍ͯ͠Ε͹ΩϟογϡՄೳ { get: (key:

    string, [cb: Function]) => string | void, set: (key: string, val: string) => void, has?: (key: string, [cb: Function]) => boolean | void // optional }
  76. ྫ: RedisClient ʹΑΔΩϟογϡ const redisClient = require('redis').createClient() const renderer =

    createRenderer({ cache: { get: (key, cb) => { redisClient.get(key, (err, res) => { // handle error if any cb(res) }) }, set: (key, val) => { redisClient.set(key, val) } } })
  77. ίϯϙʔωϯτͷΩϟογϡ • ίϯϙʔωϯτΛΩϟογϡʹରԠ͢ΔͨΊʹ͸ɺҎ ԼΛ಺༰Λ options ʹؚΊ࣮ͯ૷͢Δඞཁ͕͋Δ • name ΦϓγϣϯʹΑΔϢχʔΫͳίϯϙʔωϯτ໊ •

    serverCacheKey ؔ਺ʹΑͬͯίϯϙʔωϯτຖʹϢ χʔΫͳΩʔΛฦ͢
  78. ྫ: ίϯϙʔωϯτͷΩϟογϡରԠ export default { name: 'item', // required props:

    ['item'], serverCacheKey: props => props.item.id, render (h) { return h('div', this.item.id) } }
  79. ΩϟγϡʹΑΔ෭࡞༻ • ࣍ͷΑ͏ͳؒҧͬͨ࢖͍ํΛ͢ΔͱϨϯμϦϯάपΓͷ όάΛੜΈग़͢ͷͰ஫ҙ͕ඞཁ • άϩʔόϧঢ়ଶʹґଘ͢ΔࢠίϯϙʔωϯτͷΩϟο γϡ • εϩοτΛड͚෇͚ΔίϯϙʔωϯτͷΩϟογϡ

  80. ΩϟογϡͷϕετϓϥΫςΟε • ಉ͡ props Λड͚औͬͨΒඞͣಉ͡HTMLΛඳը͢Δί ϯϙʔωϯτʹରͯ͠Ωϟογϡ͢Δͷ͕ཧ૝ • ੩తͳHTMLΛඳը͢Δίϯϙʔωϯτ • ϦετͷΞΠςϜΛඳը͢Δίϯϙʔωϯτ

    • ϘλϯɺΞϥʔτͳͲͷҰൠతͳ UI ίϯϙʔωϯτ
  81. 2. ϋΠυϨʔγϣϯ

  82. ݱ࣮ੈքͷϋΠυϨʔγϣϯ • ϋΠυϨʔγϣϯ͸ӳޠͰ͸hydrationɻݕࡧ͢Δͱ ʮϦΞॅͷੈքʯͰ͸ɺओʹҎԼͷΑ͏ͳҙຯ • hydration: ਫ෼ิڅ • ҎԼิ଍ •

    dehydration: ୤ਫ • re-hydration: ิਫ
  83. Vue ͷੈքͰ͸ʁ • ࡶʹ͍͏ͱʮhydration: ঢ়ଶิڅʯ • DOM ͕ঢ়ଶ (JSON) Λิڅͯ͠


    ظ଴͢΂͖࢟ʹͳΔ͜ͱ DOM
  84. • αʔόαΠυͰϨϯμϦϯά͞ΕͨDOMπϦʔͱɺΫϥΠΞϯτα ΠυͰߏங͞ΕΔԾ૝ϊʔυπϦʔ͕Ұக͢Δ͔Ͳ͏͔ͷݕূͱ ࠶ߏங·ͰͷҰ࿈ͷࣄ৅ͷ͜ͱ ۩ମతʹϋΠυϨʔγϣϯͬͯʁ HTTP App (Root vue instance)

    Render Functions ... <div id="app" server-rendered="true"> ... </div> ... response hydrate JSON new Vue({ … }).$mount(‘#app’) render Virtual Node Tree Rendered DOM Tree window.__initial__ = { …. } checking set $el
  85. • αʔόαΠυͰϨϯμϦϯά͞ΕͨDOMπϦʔΛഁغͯ͠ɺΫϥΠ ΞϯταΠυͰैདྷͷVirtual DOM ͷॲཧϑϩʔͰϨϯμϦϯά αʔόͱΫϥΠΞϯτ͕Ұக͠ͳ͔ͬͨ৔߹ HTTP App (Root vue

    instance) Render Functions ... <div id="app" server-rendered="true"> ... </div> ... response hydrate JSON new Vue({ … }).$mount(‘#app’) Rendered DOM Tree window.__initial__ = { …. } checking render Virtual Node Tree diff + patch
  86. ։ൃϞʔυͱϓϩμΫγϣϯϞʔυͷҧ͍ • ։ൃϞʔυͰ͸ɺΫϥΠΞϯτଆͰੜ੒͞ΕͨԾ૝ϊʔ υπϦʔͷɺαʔόͰϨϯμϦϯά͞ΕͨDOMπϦʔͱ Ұக͍ͯ͠Δ͔Ͳ͏͔ͷݕূॲཧ͸࣮ߦ͢Δ • ϓϩμΫγϣϯϞʔυͰ͸ɺύϑΥʔϚϯεΛ࠷େԽ͢ ΔͨΊʹ͜ͷݕূΛແޮʹ͍ͯ͠Δ

  87. ϋΠυϨʔγϣϯͷ஫ҙࣄ߲ • αʔόαΠυϨϯμϦϯάͱΫϥΠΞϯτͷϋΠυϨʔ γϣϯʹ͓͍ͯɺValid ͳߏ଄Λͨ͠ HTML Λهࡌ͠ͳ ͍ͱෆҰக͕ൃੜ͢Δ <table> <tr><td>hi

    evan!</td></tr> </table> ϒϥ΢β͸ࣗಈతʹ <tbody>Λૠೖ͢Δ Vue͸ςϯϓϨʔτΛίϯύΠϧ͢Δͱ ͦͷߏ଄ͷ·· Virtual-DOM Λੜ੒͢Δ ෆਖ਼ͳ<table>ߏ଄Λ࣋ͬͨ
 ςϯϓϨʔτ
  88. 3. ίϯςΩετ

  89. • VueͰ࡞੒ͨ͠ΞϓϦέʔγϣϯίʔυ͕Πϯελϯε Խ͞ΕΔͱɺNode ϓϩηεʹ͓͍ͯΫϥΠΞϯτ͔Β དྷͨϦΫΤετؒͰڞ༗͞ΕΔ ίϯςΩετͷඞཁੑ request1 request2 requestX άϩʔόϧͳঢ়ଶ͕Ԛછ͞

    Εͯ͠·͍ɺϨϯμϦϯά ݁ՌʹѱӨڹΛٴ΅͢
  90. ίϯςΩετʹΑΔԚછͷճආ • ֤ϦΫΤετຖʹίϯςΩετΛ࡞੒ͯ͠ɺͦ͜ʹঢ়ଶ Λઃఆ͢Δ͜ͱͰɺ֤αϯυϘοΫε಺Ͱঢ়ଶ͕อޢ ͞ΕΔ request1 request2 requestX Context Context

    Context vm. runInNewContext vm. runInNewContext vm. runInNewContext
  91. ίϯςΩετͷಋೖ • αʔό޲͚ͷ Vue ΞϓϦέʔγϣϯΛ࣮ߦͤ͞ΔΤϯτ ϦϙΠϯτΛ༻ҙ͢Δ // server-entry.js import Vue

    from 'vue' import App from './App.vue' const app = new Vue(App) // όϯυϧϨϯμϥଆͰϨϯμϦϯάͰݺͼग़͢ࡍʹ౉͞ΕΔ // ίϯςΩετΛड͚औΔؔ਺Λ export ͢Δ // ؔ਺͸ Vue ΠϯελϯεΛฦ͢ඞཁ͕͋Δ export default context => { // σʔλͷϑΣον return app.fetchServerData(context.url).then(() => { return app }) }
  92. ίϯςΩετͷಋೖ • Vue ͕ఏڙ͢ΔόϯυϧϨϯμϥʹΑΓίϯςΩετʹ ରԠͨ͠ϨϯμϥΛ࡞੒ const createBundleRenderer = require('vue-server-renderer').createBundleRenderer const

    bundle = require('./dist/server-bundle.js') const rederer = createBundleRenderer(bundle)
  93. ίϯςΩετͷಋೖ • ϦΫΤετϋϯυϥ಺ͰίϯςΩετΛ࡞੒͠ɺϨϯμ ϥͷϨϯμϦϯάϝιουʹࢦఆ࣮ͯ͠ߦ // for express app.get('*', (req, res)

    => { const context = { url: req.url } const renderStream = renderer.renderToStream(context) res.write(html.head) renderStream.on('data', chunk => { ... res.write(chunk) }) renderStream.on('end', () => { res.end(html.tail) }) }) ϨϯμϦϯάͷࡍʹ༻ҙͨ͠Τ ϯτϦϙΠϯτ͕ݺ͹Εͯɺί ϯςΩετ͕౉͞ΕΔ
  94. 4. όϯυϦϯά

  95. αʔό޲͚΁όϯυϧԽ͢Δඞཁੑ • ϦΫΤετຖͷαϯυϘοΫε͸ɺΞϓϦέʔγϣϯ ίʔυΛಈ࡞ͤ͞ΔͱશͯͷґଘϞδϡʔϧ΋ҰॹʹҾ ͖ࠐΜͰಈ࡞͢Δ Node process request request load

    load ಡΈࠐ·Εͨ ґଘϞδϡʔ ϧΛɺ࠶౓ղ ੳ͠ɺධՁ͢ ΔͨΊɺύ ϑΥʔϚϯε ͸Α͘ͳ͍
  96. ґଘϞδϡʔϧΛ֎෦Խ͢Δ͜ͱͰղܾ • ґଘϞδϡʔϧΛ֎෦Խ͢Δ͜ͱʹΑΓɺαϯυϘοΫ ε্ʹ͸ɺNodeϓϩηεͰಡΈࠐ·ΕͨґଘϞδϡʔ ϧͰࢀরͯ͠ಈ࡞͢ΔΑ͏ʹͳΔ Node process request request reference

  97. αʔό޲͚ͷόϯυϧԽ (webpackͷྫ) • αʔό޲͚ʹɺґଘϞδϡʔϧΛ֎෦Խ͢ΔΑ͏ʹόϯ υϧԽͷઃఆΛ͢Δ // webpack ͷઃఆ module.exports =

    { entry: './src/server-entry.js', target: 'node', output: { ..., libraryTarget: 'commonjs2' }, // webpack ͷ externals Λར༻ͯ͠ɺpackage.json ͷ "dependencies"ͷ ݩʹ // ͋ΔϞδϡʔϧΛશͯ֎෦Խ externals: Object.keys(require('./package.json').dependencies) }
  98. αʔό޲͚ͷόϯυϧԽ • αʔόଆͰґଘϞδϡʔϧ͕֎෦Խ͞ΕͨόϯυϧϑΝ ΠϧΛҾ͖ࠐΈɺόϯυϧϨϯμϥͰͦΕΛࢦఆͯ͠Ϩ ϯμϥΛ࡞੒͢Δ const createBundleRenderer = require('vue-server-renderer').createBundleRenderer const

    bundle = require('./dist/server-bundle.js') const rederer = createBundleRenderer(bundle)
  99. αʔό޲͚όϯυϧԽͷ஫ҙࣄ߲ • ϦΫΤετؒͰڞ༗͞Ε͍ͯΔͷͰɺґଘϞδϡʔϧ͕ ႈ౳͔Ͳ͏͔֬ೝ͕ඞཁ • ҟͳΔϦΫΤετؒͰৗʹಉ͡ඳը݁ՌʹͳΔͷ͔ • ґଘϞδϡʔϧʹάϩʔόϧͳঢ়ଶΛ͍࣋ͬͯͯɺΞϓ ϦέʔγϣϯίʔυʹΑͬͯมߋ͞ΕΔ΋ͷ͍ͭͯ͸஫ ҙ͕ඞཁ

  100. αʔόαΠυϨϯμϦϯά ʹ͓͚Δ όϯυϧԽͷΠϝʔδ

  101. όϯυϧԽͷΠϝʔδ(webpack)

  102. αʔόαΠυʹ͓͚Δ Vue ͷ API

  103. ϥΠϑαΠΫϧϑοΫ • beforeCreate • created
 
 
 
 
 


    
 
 
 
 
 • beforeMount • mounted • beforeUpdate • updated • activated • deactivated • beforeDestroy • destroyed ݺ͹ΕΔϑοΫ ݺ͹Εͳ͍ϑοΫ
  104. ϥΠϑαΠΫϧϑοΫҎ֎ • Ͳͷ API ͕αʔόαΠυͰಈ࡞͢Δ͔Ͳ͏͔͸ɺݫີʹ ͸ॻ͔Ε͍ͯͳ͍ • DOM ʹґଘ͍ͯ͠ͳ͍ܥ౷ͷ΋ͷ͸ɺಈ࡞͢Δ͸ͣ •

    Πϕϯτ: $emit, $off, $on, $once • σʔλܥ: $watch, $set, $delete, $data, ͳͲ • ͦͷଞ΋Ζ΋Ζ …
  105. αʔόαΠυϨϯμϦϯά Example

  106. vue-hackernews-2.0 • ެࣜͰఏڙ͢ΔαʔόαΠυϨϯμϦϯά example
 https://github.com/vuejs/vue-hackernews-2.0

  107. ·ͱΊ

  108. ϨϯμϦϯάγεςϜ • Vue ͷϨϯμϦϯάγεςϜ͸ɺ࠷దԽͱϦΞΫςΟϒ γεςϜͱ૊Έ߹ΘͤΔ͜ͱʹΑΓɺಛʹҙࣝ͠ͳͯ͘ ΋଎͍ϨϯμϦϯάΛఏڙ͍ͯ͠Δ • ·ͨɺ೚ҙͰϨϯμϦϯάΛ੍ޚͰ͖Δ࢓૊ΈΛఏڙ͢ Δ͜ͱͰɺ͞ΒͳΔύϑΥʔϚϯεͷ޲্΋Մೳʹͳͬ ͍ͯΔ

  109. αʔόαΠυϨϯμϦϯά • ެࣜʹఏڙ͢ΔϥΠϒϥϦͱπʔϧʹΑͬͯɺαʔόα ΠυϨϯμϦϯάΛ༰қʹ࣮ݱ͢Δ͜ͱ͕Մೳʹͳͬͨ • ͜ΕʹΑΓɺαʔόαΠυͱΫϥΠΞϯταΠυͷ྆ํ ʹରԠՄೳͳɺuniversal/isomorphic ͳΞϓϦέʔγϣ ϯߏங͕Մೳʹͳͬͨ

  110. ͱ͍͏Θ͚Ͱɺ

  111. universal / isomorphic ͳ ίϯϙʔωϯτΛ࡞Δʹ͸ʁ

  112. ༩͑ΒΕͨσʔλʹରͯ͠ ৗʹಉ͡ϨϯμϦϯά݁ՌʹͳΔ ؔ਺ܕͳίϯϙʔωϯτΛ ࣮૷Λ͢Δ͜ͱʂ

  113. Ҏ্ʂ

  114. one more thing …

  115. Vue.js ೔ຊޠެࣜαΠτ Coming soon!! Vue.js ೔ຊޠެࣜαΠτ

  116. ೔ຊਓ޲͚ Vue.js ίϛϡχςΟ • URL
 https://vuejs-jp-slackin.herokuapp.com • Vue.js ೔ຊޠެࣜαΠτܦ༝Ͱ΋ࢀՃͰ͖·͢
 http://jp.vuejs.org


  117. ͝੩ௌ ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ