Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Vue.js 2.0 Server Side Rendering
Search
kazupon
November 13, 2016
Programming
12k
46
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Vue.js 2.0 Server Side Rendering
Nodefest 2016 Nov 13
kazupon
November 13, 2016
More Decks by kazupon
See All by kazupon
プラグインで拡張される Context をtype-safe にする難しさと設計判断
kazupon
2
3.1k
Oxlint JS plugins
kazupon
1
1.4k
gunshi
kazupon
1
280
Nitro v3
kazupon
2
630
わたしのOSS活動
kazupon
3
670
Vapor Revolution
kazupon
3
4.4k
Vue.js最新動向
kazupon
3
1.7k
Vue 3.4
kazupon
13
5k
Vue & Vite Rustify
kazupon
4
2.5k
Other Decks in Programming
See All in Programming
AIがコードを書いてくれる時代、我々は何を確かめるのか
yosuke_furukawa
PRO
13
5.7k
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
3
1.4k
Engineering Biometric UX Across Android Versions | DroidKnights 2026
ryunen344
1
180
當我們開始不讀 Code - AI Agent 時代,Code Review 與 Clean Code 還剩下什麼?
jame2408
1
360
Crash Auto Pipelines
veronikapj
1
380
Vue.jsで作る空間解析アプリとCapacitorプラグインのData Bridge
hal_spidernight
1
160
SODA - FACT BOOK(JP)
sodainc
1
40k
AI時代のIaC入門 〜なぜインフラをコードで管理したいのか?〜 / Introduction to IaC in the AI Era
akihisaikeda
6
1.4k
Seven New Principles of Software Engineering
yegor256
0
460
Getting Started with Vibe Coding
miccheng
0
180
TanStack Vue Query と Pinia Colada から学ぶ非同期状態の型設計
aoshi
0
620
느린 네트워크와 저사양 디바이스 사용자를 위한 웹뷰 로딩 시간 개선기
kmkim
1
200
Featured
See All Featured
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3.1k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.5k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.6k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
740
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
320
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
440
My Coaching Mixtape
mlcsv
0
380
Abbi's Birthday
coloredviolet
4
11k
The Cult of Friendly URLs
andyhume
79
7.1k
How Software Deployment tools have changed in the past 20 years
geshan
3
35k
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
3
1.2k
Transcript
Vue.js 2.0 αʔόαΠυϨϯμϦϯά ౦ژNodeֶԂࡇ2016 2016-11-13 @kazupon
ࣗݾհ
Vue.js Core Team member https://github.com/kazupon
vuejs-jp ༗ࢤͰٕज़ධ༷ࣾʹͯ Web هࣄ࿈ࡌத http://gihyo.jp/dev/serial/01/vuejs
We are building Open Innovation Platform!! https://cuusoo.com
Vue.js ͱʁ
࡞ऀ Evan You ※ ࡞ऀͷΠϯλϏϡʔهࣄ: Between the Wires | Evan
You https://betweenthewires.org/between-the-wires-evan-you-cb56660bc8a4#.6b0vzpgzw ※ ࡞ऀͷαΠτ http://evanyou.me
ϓϩάϨογϒϑϨʔϜϫʔΫ
※ 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 ຊମ
• 201610݄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
2.0 Ͱͷେ͖͍มߋ
ϨϯμϦϯάγεςϜ͕৽ʂ • Virtual DOM ΞʔΩςΫνϟΛ࠾༻ • Evan You ࢯʹΑΔϑϧεΫϥον࣮ •
2िؒͨΒͣͰpre-alphaόʔδϣϯΛ࣮
Virtual DOM ʹΑΔޮೳ
ϨϯμϦϯάͷߴԽ ※ The Vue Point: Vue 2.0 is Here (Vue.js
ެࣜϒϩά) https://medium.com/the-vue-point/vue-2-0-is-here-ef1f26acf4b8#.v9xl2x8f7
αʔόαΠυϨϯμϦϯά Request Response Client Server render
ॊೈͳϨϯμϦϯάखஈ • એݴతϨϯμϦϯά • ςϯϓϨʔτ • ໋ྩతϨϯμϦϯά • ԾϊʔυΛར༻ͨ͠ JavaScript
࣮ • hyperscript / JSX
ΫϩεϓϥοτϑΥʔϜରԠ • ϚϧνϞόΠϧσόΠε͚ͷϑϨʔϜϫʔΫ ※ weex https://alibaba.github.io/weex/
ΞδΣϯμ
ࠓ͢͜ͱ • ϨϯμϦϯάγεςϜ • αʔόαΠυϨϯμϦϯά
ϨϯμϦϯάγεςϜ
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>
෦Ͱ৭ʑͱΰχϣΰχϣ͢Δ ॳظϨϯμϦϯάྃ ࠶ϨϯμϦϯά
ҰൠతͳϨϯμϦϯάͷྲྀΕͰ ෦ʹ͍ͭͯݟ͍͖ͯ·͠ΐ͏ʂ
ҰൠతͳϨϯμϦϯάͷྲྀΕ optimize diff + patch compile generate rendering track dependencies
AST Optimized AST Virtual DOM
ίϯύΠϧ
ςϯϓϨʔτΛ 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
ςϯϓϨʔτύʔα • ςϯϓϨʔτύʔαɺJohn Resig ࢯͷͷΛ fork ͠ ͯ Vue ͚ʹಠࣗʹΧελϚΠζ
※ ςϯϓϨʔτύʔα https://github.com/vuejs/vue/blob/dev/src/compiler/parser/html-parser.js ES2015 Ͱ re-write & ࠷దԽ
࠷దԽ
Ұൠతͳ Virtual DOM New Virtual Node Tree Old Virtual Node
Tree diff + patch ԾϊʔυπϦʔͷ diff ࢉग़ίετ͕͔͔Δ
• Virtual DOM ʹΑΔϨϯμϦϯάͷύϑΥʔϚϯεΛΑ ͘͢ΔͨΊʹɺVue Ͱ AST ʹରͯ͠ҎԼͷ̎ஈ֊ͷॲ ཧΛͯ͠࠷దԽ͢Δ
1. ੩తͳϊʔυͷݕग़ 2. ੩తͳϊʔυπϦʔͷݕग़ AST ʹର͢Δ࠷దԽॲཧ
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 ཁૉΛ ੩తͳϊʔυͱͯ͠ݕग़
• ݕग़͞Εͨϊʔυɺ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', … }] }], … }] }
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 ཁૉ͕ ੩తͳϊʔυπϦʔͱͯ͠ݕग़
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, … }], … } ], … } ] }
ϨϯμϦϯάؔͷੜ
AST ͔ΒϨϯμϦϯάؔΛੜ • ҎԼͷؔΛੜ͢Δ • render ؔ • staticRenderFns ؔ܊
(ྻ) • ͜ΕΒؔɺVue Πϯελϯ εͷ $options ʹ֨ೲ͞ΕΔ Optimized AST
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) ]) } ࠷దԽʹΑΓݕग़͞Εͨ੩తͳϊʔυπϦʔͷ෦ɺ ෦ϝιουʹϚοϐϯά
staticRenderFns ؔ܊ • ࠷దԽʹΑΓ AST Ͱݕग़ͨ͠੩తͳϊʔυπϦʔɺ ԾϊʔυπϦʔͱͯ͠ฦ͢Α͏ʹੜͨؔ͠Λྻ ʹ֨ೲ͢Δ [ function
anonymous () { with (this) { return _h('div', { staticClass: 'content' }, [ _h('p', ['This is content']) ]) }} ]
ϨϯμϦϯά
ϦΞΫςΟϒγεςϜʹΑΔϨϯμϦϯά diff + patch create call Virtual Node Tree notify
Watcher ʹΑΔσʔλมߋͷࢹ • σʔλґଘؔΛ͠ɺσʔλมߋΛࢹ͢Δ • σʔλมߋݕग़ͷɺ Watcher ෦ͷ _render ϝ
ιουΛݺͼग़ͯ͠࠶ϨϯμϦϯά const Component = { props: ['msg'], data () { return { title: 'hello', items: […] } }, … } msg data/props Watcher title items 0 x … Collect Dependencies
ԾϊʔυπϦʔͷੜ • 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
ԾϊʔυπϦʔͷΩϟγϡԽͱϚʔΩϯά • staticRenderFns ͷ࣮ߦ݁ՌͰಘΒΕΔ੩తͳԾϊʔυ πϦʔɺ࠷ॳͷϨϯμϦϯάͷࡍʹ͜ΕΒ݁ՌΛ Vue Πϯελϯε෦ʹΩϟογϡ͢Δ • ͜ͷ࣌ɺԾϊʔυπϦʔʹ isStatic
= true ͰϚʔΩϯ ά͢Δ͜ͱͰɺޙͷ Virtual DOM ͷ diff ʹ͓͍ͯεΩο ϓ͞ΕΔ • ࠶ϨϯμϦϯά࣌ʹɺΩϟογϡԽ͞ΕͨͷΛར༻
Vue ͷ Virtual DOM • Virtual DOM snabbdom Λ
fork ͯ͠ಠࣗʹΧελϚΠ ζͨ͠ͷ https://github.com/snabbdom/snabbdom
Virtual DOM ͷ diff / patch • diff / patch
جຊ snabbdom ϕʔεͰɺVue ͷ࠷దԽॲ ཧʹΑͬͯ diff ΛεΩοϓ͢Δ͜ͱͰɺDOM Λੜ͢Δ ·ͰॲཧίετΛݮ https://github.com/vuejs/vue/blob/dev/src/core/vdom/patch.js
ԾϊʔυπϦʔͷੜ͔Β Virtual DOM ʹΑΔॲཧ·Ͱͷ Πϝʔδ
ॳظͷϨϯμϦϯά return caching & marking create diff + patch skip
diff of the marked tree
ߋ৽࣌ͷ࠶ϨϯμϦϯά return create diff + patch skip diff of the
marked tree
ίϯϙʔωϯτπϦʔ ͷ ϨϯμϦϯά
• ֤ίϯϙʔωϯτຖʹ Watcher Λհͯ͠τοϓμϯత ʹϨϯμϦϯά Ұ൪τοϓ͔Βࢠʹ͔ͬͯϨϯμϦϯά Watcher track dependencies component
Root (new Vue)
• ίϯϙʔωϯτͷ data/props ͕ɺଞʹґଘ͕ͳ͘ɺ ͦͷίϯϙʔωϯτͷΈͳΒɺͦͷίϯϙʔωϯτͩ ͚࠶ϨϯμϦϯά ίϯϙʔωϯτʹดͨ͡σʔλͷมߋݕग़ Root (new Vue)
• ίϯϙʔωϯτͷ data/props ͕ɺଞͷࢠίϯϙʔω ϯτʹόέπϦϨʔ͍ͯ͠Δ߹ɺόέπϦϨʔઌͷ ࢠίϯϙʔωϯτ࠶ϨϯμϦϯά σʔλͷ୯ํόΠϯσΟϯά pass props Root
(new Vue)
• ࢠίϯϙʔωϯτ͕ίϯϙʔωϯτͱv-modelͰํ σʔλόΠϯσΟϯά͍ͯ͠Δ߹ɺʹσʔλม ߋΛ௨ͨ͠߹ɺࢠ࠶ϨϯμϦϯά͢Δ v-modelʹΑΔํόΠϯσΟϯά pass props emit events Root
(new Vue)
ଞͷ ϨϯμϦϯάγεςϜ ͱͷൺֱ
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
͞ΒͳΔ࠷దԽʹ͚ͯ
࠷దԽ߲ • ςϯϓϨʔτͷࣄલίϯύΠϧ + ϥϯλΠϜ • v-for ʹΑΔϦετϨϯμϦϯά࣌ʹ͓͚Δ key ଐੑ
• render ؔʹΑΔύϑΥʔϚϯενϡʔχϯά࣮ • ؔܕίϯϙʔωϯτ (functional component)
αʔόαΠυϨϯμϦϯά
αʔόαΠυϨϯμϦϯάͷॏཁੑ • γϯάϧϖʔδΞϓϦέʔγϣϯʹΑΓϢʔβʔʹ৺ ྑ͍UXΛఏڙͰ͖ΔΑ͏ʹͳͬͨ • ͕ɺҎԼͷ͕͋Δ • SEOରࡦ • ॳظදࣔͷϩʔσΟϯά࣌ؒ
ैདྷͷVueͰ͔ͬͨ͠ • Vue 2.0 ҎલͷόʔδϣϯͰɺυΩϡϝϯτϑϥάϝϯ τʹΑΔੜDOMϕʔεʹΑΔϨϯμϦϯάͷͨΊɺίΞ ଆͰαϙʔτ͍ͯ͠ͳ͔ͬͨ • ରԠ͢ΔʹɺαʔυϕϯμͷϨϯμϥΛར༻͢Δ͔ɺ ಠࣗʹରԠ͢Δඞཁ͕͋ͬͨ
• ͞ΒʹɺϋΠυϨʔγϣϯͷΈɺΫϥΠΞϯταΠ υͷϥΠϒϥϦͷαʔόαΠυରԠͳͲɺશ෦ಠࣗʹର Ԡ͢Δඞཁ͕͋ͬͨ
Vue 2.0 Ͱڥ͕େ͖͘վળ • Virtual DOM ʹΑΓநԽ͞ΕͨϨϯμϦϯά • ϋΠυϨʔγϣϯͷΈ •
ϢχόʔαϧରԠ͞Εͨެࣜʹఏڙ͢ΔϥΠϒϥϦ • Node.js ͚ʹϨϯμϥ • ίϯςΩετʹΑΔႈੑΛอূ͢ΔϨϯμϦϯά • αʔό͚ʹ࠷దԽ͞ΕͨϞδϡʔϧͷόϯυϦϯά
• Vue 2.0 Ҏ߱ͰɺҎԼͷެࣜϥΠϒϥϦͱόϯυϦϯ άπʔϧͰɺαʔόαΠυϨϯμϦϯάΛ༰қʹ࣮ݱ͢ Δ͜ͱ͕Ͱ͖Δ ͬͨαʔόαΠυϨϯμϦϯάڥ vue vuex vue-router
vue-server-renderer Vue library stack + and other …
Vue 2.0 ʹ͓͚Δ αʔόαΠυϨϯμϦϯά ͷྲྀΕʹ͍ͭͯݟ͍͖ͯ·͠ΐ͏ʂ
Client Server αʔόଆͰɺVueͰ࡞ΒΕͨ ΞϓϦέʔγϣϯίʔυ͕ αʔόଆͰಈ࡞͢ΔΑ͏όϯ υϧԽ͞Εͨͷ͕ಡΈࠐ·Ε ͯಈ࡞ ίϯϙʔωϯτΛαʔόଆ ͰϨϯμϦϯά͢ΔͨΊͷ ϨϯμϥΠϯελϯεԽ
Client Server ϦΫΤετ GET /:user_id/profile ϢʔβʔʹΑΔΞΫηε ɾɾɾ ϦΫΤετຖʹ αϯυϘοΫεΛ࡞ͯ͠ ίϯςΩετΛࢦఆͯ͠
ΤϯτϦϙΠϯτͷ Vue Λ࣮ߦͤ͞Δ
Client Server route ʹରԠ͢Δ ίϯϙʔωϯτΛ ಈ࡞ͤ͞ɺσʔλ ΛϑΣον ɾɾɾ ΫϥΠΞϯτʹ͢ॳظঢ়ଶΛJSONͱ͠ ͯຒΊࠐΉΑ͏ʹ
HTMLϨϯμϦϯάͯ͠ϨεϙϯεΛฦ͢
Client Server Ϩεϙϯε Ϛϯτ&ϋΠυϨʔτ ΫϥΠΞϯταʔό͔ΒϨϯμϦϯά͞Ε ͨHTMLͱΫϥΠΞϯτ͚ʹόϯυϧԽ͞ ΕͨΞϓϦέʔγϣϯίʔυ͕৴͞ΕΔ ϒϥβଆͰHTMLΛϩʔυͨ͠ ޙɺΤϯτϦϙΠϯτͱͳΔVueΛ ಈ࡞ͤ͞ɺϚϯτ&ϋΠυϨʔτ
ʹΑ࣮ͬͯࡍʹ༰Λදࣔ͢Δ
Client Server ޙɺΫϥΠΞϯτଆͰ ϧʔςΟϯάΛߦ͍ɺ ඞཁʹԠͯ͡σʔλΛϑΣονͯ͠ ϨϯμϦϯά͢Δ
αʔόαΠυϨϯμϦϯάΛߏ͢Δ4ཁૉ • 1. Ϩϯμϥ • 2. ϋΠυϨʔγϣϯ • 3. ίϯςΩετ
• 4. όϯυϦϯά
1. Ϩϯμϥ
ఏڙ͢ΔϨϯμϥ • Vue ΞϓϦέʔγϣϯΛαʔόαΠυͰϨϯμϦϯά͢ ΔͨΊͷ Node.js ڥͰಈ࡞͢ΔϨϯμϦϯάϞδϡʔ ϧ • Ϩϯμϥɺࢦఆ͞Εͨ
Vue ΞϓϦέʔγϣϯͷrender ؔʹΑͬͯऔಘͨ͠ԾϊʔυπϦʔΛ walk ͯ͠ HTML จࣈྻͱͯ͠ϨϯμϦϯά
جຊతͳ͍ํ • 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> })
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>') }) })
ΩϟγϡʹΑΔߴԽ • Φϓγϣϯʹ cache ΦϒδΣΫτΛࢦఆ͢Δ͜ͱͰɺί ϯϙʔωϯτͷඳը݁ՌΛΩϟογϯά͢Δ͜ͱʹΑ Γɺ͞ΒͳΔύϑΥʔϚϯεΛ্͕Մೳ const LRU =
require('lru-cache') const renderer = createRenderer({ cache: LRU({ max: 10000 }) })
Ωϟγϡʹ͓͚ΔඞࢸΠϯλʔϑΣΠε • Φϓγϣϯʹ ࢦఆ͢Δ cache ΦϒδΣΫτɺҎԼͷ ΠϯλʔϑΣΠεΛ࣮͍ͯ͠ΕΩϟογϡՄೳ { get: (key:
string, [cb: Function]) => string | void, set: (key: string, val: string) => void, has?: (key: string, [cb: Function]) => boolean | void // optional }
ྫ: 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) } } })
ίϯϙʔωϯτͷΩϟογϡ • ίϯϙʔωϯτΛΩϟογϡʹରԠ͢ΔͨΊʹɺҎ ԼΛ༰Λ options ʹؚΊ࣮ͯ͢Δඞཁ͕͋Δ • name ΦϓγϣϯʹΑΔϢχʔΫͳίϯϙʔωϯτ໊ •
serverCacheKey ؔʹΑͬͯίϯϙʔωϯτຖʹϢ χʔΫͳΩʔΛฦ͢
ྫ: ίϯϙʔωϯτͷΩϟογϡରԠ export default { name: 'item', // required props:
['item'], serverCacheKey: props => props.item.id, render (h) { return h('div', this.item.id) } }
ΩϟγϡʹΑΔ෭࡞༻ • ࣍ͷΑ͏ͳؒҧ͍ͬͨํΛ͢ΔͱϨϯμϦϯάपΓͷ όάΛੜΈग़͢ͷͰҙ͕ඞཁ • άϩʔόϧঢ়ଶʹґଘ͢ΔࢠίϯϙʔωϯτͷΩϟο γϡ • εϩοτΛड͚͚ΔίϯϙʔωϯτͷΩϟογϡ
ΩϟογϡͷϕετϓϥΫςΟε • ಉ͡ props Λड͚औͬͨΒඞͣಉ͡HTMLΛඳը͢Δί ϯϙʔωϯτʹରͯ͠Ωϟογϡ͢Δͷ͕ཧ • ੩తͳHTMLΛඳը͢Δίϯϙʔωϯτ • ϦετͷΞΠςϜΛඳը͢Δίϯϙʔωϯτ
• ϘλϯɺΞϥʔτͳͲͷҰൠతͳ UI ίϯϙʔωϯτ
2. ϋΠυϨʔγϣϯ
ݱ࣮ੈքͷϋΠυϨʔγϣϯ • ϋΠυϨʔγϣϯӳޠͰhydrationɻݕࡧ͢Δͱ ʮϦΞॅͷੈքʯͰɺओʹҎԼͷΑ͏ͳҙຯ • hydration: ਫิڅ • ҎԼิ •
dehydration: ਫ • re-hydration: ิਫ
Vue ͷੈքͰʁ • ࡶʹ͍͏ͱʮhydration: ঢ়ଶิڅʯ • DOM ͕ঢ়ଶ (JSON) Λิڅͯ͠
ظ͖࢟͢ʹͳΔ͜ͱ DOM
• αʔόαΠυͰϨϯμϦϯά͞Εͨ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
• αʔόαΠυͰϨϯμϦϯά͞Εͨ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
։ൃϞʔυͱϓϩμΫγϣϯϞʔυͷҧ͍ • ։ൃϞʔυͰɺΫϥΠΞϯτଆͰੜ͞ΕͨԾϊʔ υπϦʔͷɺαʔόͰϨϯμϦϯά͞ΕͨDOMπϦʔͱ Ұக͍ͯ͠Δ͔Ͳ͏͔ͷݕূॲཧ࣮ߦ͢Δ • ϓϩμΫγϣϯϞʔυͰɺύϑΥʔϚϯεΛ࠷େԽ͢ ΔͨΊʹ͜ͷݕূΛແޮʹ͍ͯ͠Δ
ϋΠυϨʔγϣϯͷҙࣄ߲ • αʔόαΠυϨϯμϦϯάͱΫϥΠΞϯτͷϋΠυϨʔ γϣϯʹ͓͍ͯɺValid ͳߏΛͨ͠ HTML Λهࡌ͠ͳ ͍ͱෆҰக͕ൃੜ͢Δ <table> <tr><td>hi
evan!</td></tr> </table> ϒϥβࣗಈతʹ <tbody>Λૠೖ͢Δ VueςϯϓϨʔτΛίϯύΠϧ͢Δͱ ͦͷߏͷ·· Virtual-DOM Λੜ͢Δ ෆਖ਼ͳ<table>ߏΛ࣋ͬͨ ςϯϓϨʔτ
3. ίϯςΩετ
• VueͰ࡞ͨ͠ΞϓϦέʔγϣϯίʔυ͕Πϯελϯε Խ͞ΕΔͱɺNode ϓϩηεʹ͓͍ͯΫϥΠΞϯτ͔Β དྷͨϦΫΤετؒͰڞ༗͞ΕΔ ίϯςΩετͷඞཁੑ request1 request2 requestX άϩʔόϧͳঢ়ଶ͕Ԛછ͞
Εͯ͠·͍ɺϨϯμϦϯά ݁ՌʹѱӨڹΛٴ΅͢
ίϯςΩετʹΑΔԚછͷճආ • ֤ϦΫΤετຖʹίϯςΩετΛ࡞ͯ͠ɺͦ͜ʹঢ়ଶ Λઃఆ͢Δ͜ͱͰɺ֤αϯυϘοΫεͰঢ়ଶ͕อޢ ͞ΕΔ request1 request2 requestX Context Context
Context vm. runInNewContext vm. runInNewContext vm. runInNewContext
ίϯςΩετͷಋೖ • αʔό͚ͷ 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 }) }
ίϯςΩετͷಋೖ • Vue ͕ఏڙ͢ΔόϯυϧϨϯμϥʹΑΓίϯςΩετʹ ରԠͨ͠ϨϯμϥΛ࡞ const createBundleRenderer = require('vue-server-renderer').createBundleRenderer const
bundle = require('./dist/server-bundle.js') const rederer = createBundleRenderer(bundle)
ίϯςΩετͷಋೖ • ϦΫΤετϋϯυϥͰίϯςΩετΛ࡞͠ɺϨϯμ ϥͷϨϯμϦϯάϝιουʹࢦఆ࣮ͯ͠ߦ // 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) }) }) ϨϯμϦϯάͷࡍʹ༻ҙͨ͠Τ ϯτϦϙΠϯτ͕ݺΕͯɺί ϯςΩετ͕͞ΕΔ
4. όϯυϦϯά
αʔό͚όϯυϧԽ͢Δඞཁੑ • ϦΫΤετຖͷαϯυϘοΫεɺΞϓϦέʔγϣϯ ίʔυΛಈ࡞ͤ͞ΔͱશͯͷґଘϞδϡʔϧҰॹʹҾ ͖ࠐΜͰಈ࡞͢Δ Node process request request load
load ಡΈࠐ·Εͨ ґଘϞδϡʔ ϧΛɺ࠶ղ ੳ͠ɺධՁ͢ ΔͨΊɺύ ϑΥʔϚϯε Α͘ͳ͍
ґଘϞδϡʔϧΛ֎෦Խ͢Δ͜ͱͰղܾ • ґଘϞδϡʔϧΛ֎෦Խ͢Δ͜ͱʹΑΓɺαϯυϘοΫ ε্ʹɺNodeϓϩηεͰಡΈࠐ·ΕͨґଘϞδϡʔ ϧͰࢀরͯ͠ಈ࡞͢ΔΑ͏ʹͳΔ Node process request request reference
αʔό͚ͷόϯυϧԽ (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) }
αʔό͚ͷόϯυϧԽ • αʔόଆͰґଘϞδϡʔϧ͕֎෦Խ͞ΕͨόϯυϧϑΝ ΠϧΛҾ͖ࠐΈɺόϯυϧϨϯμϥͰͦΕΛࢦఆͯ͠Ϩ ϯμϥΛ࡞͢Δ const createBundleRenderer = require('vue-server-renderer').createBundleRenderer const
bundle = require('./dist/server-bundle.js') const rederer = createBundleRenderer(bundle)
αʔό͚όϯυϧԽͷҙࣄ߲ • ϦΫΤετؒͰڞ༗͞Ε͍ͯΔͷͰɺґଘϞδϡʔϧ͕ ႈ͔Ͳ͏͔֬ೝ͕ඞཁ • ҟͳΔϦΫΤετؒͰৗʹಉ͡ඳը݁ՌʹͳΔͷ͔ • ґଘϞδϡʔϧʹάϩʔόϧͳঢ়ଶΛ͍࣋ͬͯͯɺΞϓ ϦέʔγϣϯίʔυʹΑͬͯมߋ͞ΕΔͷ͍ͭͯ ҙ͕ඞཁ
αʔόαΠυϨϯμϦϯά ʹ͓͚Δ όϯυϧԽͷΠϝʔδ
όϯυϧԽͷΠϝʔδ(webpack)
αʔόαΠυʹ͓͚Δ Vue ͷ API
ϥΠϑαΠΫϧϑοΫ • beforeCreate • created
• beforeMount • mounted • beforeUpdate • updated • activated • deactivated • beforeDestroy • destroyed ݺΕΔϑοΫ ݺΕͳ͍ϑοΫ
ϥΠϑαΠΫϧϑοΫҎ֎ • Ͳͷ API ͕αʔόαΠυͰಈ࡞͢Δ͔Ͳ͏͔ɺݫີʹ ॻ͔Ε͍ͯͳ͍ • DOM ʹґଘ͍ͯ͠ͳ͍ܥ౷ͷͷɺಈ࡞͢Δͣ •
Πϕϯτ: $emit, $off, $on, $once • σʔλܥ: $watch, $set, $delete, $data, ͳͲ • ͦͷଞΖΖ …
αʔόαΠυϨϯμϦϯά Example
vue-hackernews-2.0 • ެࣜͰఏڙ͢ΔαʔόαΠυϨϯμϦϯά example https://github.com/vuejs/vue-hackernews-2.0
·ͱΊ
ϨϯμϦϯάγεςϜ • Vue ͷϨϯμϦϯάγεςϜɺ࠷దԽͱϦΞΫςΟϒ γεςϜͱΈ߹ΘͤΔ͜ͱʹΑΓɺಛʹҙࣝ͠ͳͯ͘ ͍ϨϯμϦϯάΛఏڙ͍ͯ͠Δ • ·ͨɺҙͰϨϯμϦϯάΛ੍ޚͰ͖ΔΈΛఏڙ͢ Δ͜ͱͰɺ͞ΒͳΔύϑΥʔϚϯεͷ্Մೳʹͳͬ ͍ͯΔ
αʔόαΠυϨϯμϦϯά • ެࣜʹఏڙ͢ΔϥΠϒϥϦͱπʔϧʹΑͬͯɺαʔόα ΠυϨϯμϦϯάΛ༰қʹ࣮ݱ͢Δ͜ͱ͕Մೳʹͳͬͨ • ͜ΕʹΑΓɺαʔόαΠυͱΫϥΠΞϯταΠυͷ྆ํ ʹରԠՄೳͳɺuniversal/isomorphic ͳΞϓϦέʔγϣ ϯߏங͕Մೳʹͳͬͨ
ͱ͍͏Θ͚Ͱɺ
universal / isomorphic ͳ ίϯϙʔωϯτΛ࡞Δʹʁ
༩͑ΒΕͨσʔλʹରͯ͠ ৗʹಉ͡ϨϯμϦϯά݁ՌʹͳΔ ؔܕͳίϯϙʔωϯτΛ ࣮Λ͢Δ͜ͱʂ
Ҏ্ʂ
one more thing …
Vue.js ຊޠެࣜαΠτ Coming soon!! Vue.js ຊޠެࣜαΠτ
ຊਓ͚ Vue.js ίϛϡχςΟ • URL https://vuejs-jp-slackin.herokuapp.com • Vue.js ຊޠެࣜαΠτܦ༝ͰࢀՃͰ͖·͢ http://jp.vuejs.org
͝੩ௌ ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ