KEMBAR78
Vue.js и его брат-близнец Vue-server.js / Андрей Солодовников (НГС) | PDF
Vue.js
и его брат-близнец
VueServer.js
Андрей Солодовников
1.4
Vue [Вю] (франц.) — Вид
Vue [Вю] (франц.) — Вид
Vue → View [Вью]
5 лет
Frontend/JavaScript
developer
7 лет
Велосипедист
Недвижимость
Вся
Россия
Недвижимость
Вся
Россия
2 года
в разработке
НГС.НЕДВИЖИМОСТЬ
realty.ngs.ru
НГС.НЕДВИЖИМОСТЬ
realty.ngs.ru
Сложный Frontend:
что выбрать?
WEB COMPONENTS
React (v15.1.0)Vue.js (v1.0.24)
React (v15.1.0)
43k
Vue.js (v1.0.24)
20kЗвездочек на GitHub
React (v15.1.0)
43k
IE9+
147 (43) kb
Vue.js (v1.0.24)
20k
IE9+
76 (26) kb
Звездочек на GitHub
Поддержка
Размер
React (v15.1.0)
43k
IE9+
147 (43) kb
550ms
Vue.js (v1.0.24)
20k
IE9+
76 (26) kb
450ms
Звездочек на GitHub
Поддержка
Размер
Стартует за*
* В моём личном тесте
Application
List
Item x250
Evan You
Data
Data
+ watchers
Data
+ watchers
DOM
Data
Data
+ watchers
DOM
Data
+ watchers
Reactive
Bindings
Директивы
v-if
v-for
v-show
v-text
v-html
v-bind
v-on
v-if
v-for
v-show
v-text
v-html
v-bind
v-on
ng-if
ng-repeat
ng-show
ng-bind
ng-bind-html
ng-style, ng-class...
ng-click, ng-change...
<div v-if="false">Не отрисуется</div>
<div v-else>Отрисуется</div>
<div v-if="false">Не отрисуется</div>
<div v-else>Отрисуется</div>
<div>Отрисуется</div>
<div v-bind:class=" 'foo' "></div>
<div v-bind:class=" 'foo' "></div>
<div :class=" 'foo' "></div>
<div v-bind:class=" 'foo' "></div>
<div :class=" 'foo' "></div>
<div :class=" ['foo', {bar: true}] "></div>
<div class="foo"></div>
<div class="foo"></div>
<div class="foo bar"></div>
Усатые выражения
<div>{{ someText }}</div>
<div>{{ someText }}</div>
<div>{{* someText }}</div>
<div>{{ someText }}</div>
<div>{{* someText }}</div>
<div>{{{ someHtml }}}</div>
<div>{{ someText }}</div>
<div>{{* someText }}</div>
<div>{{{ someHtml }}}</div>
<div title="Было {{pubDate}}">
<div>{{ someText }}</div>
<div>{{* someText }}</div>
<div>{{{ someHtml }}}</div>
<div title="Было {{pubDate}}">
<div title="Было {{pubDate | dateFull}}">
Lifecycle + Hooks
Data Scope
Template + Children
Destroy
Attach
created
compiled
ready
destroyed
Data Scope
Template + Children
Destroy
Attach
created
compiled
ready
destroyed
beforeDestroy
beforeCompiled
Data Scope
Template + Children
Destroy
Attach
created
compiled
ready
destroyed
beforeDestroy
beforeCompiled
activate
Создание компонентов
export default {
// ...
}
Создание компонентов
template: '<h1>Hello world</h1>',
template: '<h1>Hello world</h1>',
data () {
return { cats: 1, dogs: 2 };
}
template: '<h1>Hello world</h1>',
data () {
return { cats: 1, dogs: 2 };
},
methods: { … }
template: '<h1>Hello world</h1>',
data () {
return { cats: 1, dogs: 2 };
},
methods: { … },
computed: {
summ () { return this.cats + this.dogs; } // 3
}
created () { … }
beforeCompiled () { … }
compiled () { … }
activate () { … }
ready () { … }
beforeDestroy () { … }
destroyed () { … }
Vue.component('MyBlock', { … });
Vue.component('MyBlock', { … });
export default {
// ...
components: {
MyBlock: { … }
}
}
<my-block></my-block>
<my-block></my-block>
<component is="MyBlock"></component>
<my-block></my-block>
<component is="MyBlock"></component>
<tbody
is="MyBlock"
v-for="block in blocks"
></tbody>
const Root = {
el: 'body',
template: '<div>...</div>'
};
new Vue(Root);
Динамические компоненты
template: '<component :is=" name + 'Page' "></component>',
data: {
name: 'Main'
}
template: '<component :is=" name + 'Page' "></component>',
data: {
name: 'Main'
},
components: {
MainPage: {...},
ArticlesPage: {...}
}
Главная
template: '<component :is=" name + 'Page' "></component>',
data: {
name: 'Articles'
},
components: {
MainPage: {...},
ArticlesPage: {...}
}
Статьи
Обработка событий
<button v-on:click="onButtonClick($event)"></button>
<button v-on:click="isVisible = !isVisible"></button>
Обработка событий
<button v-on:click="onButtonClick($event)"></button>
<button v-on:click="isVisible = !isVisible"></button>
<button @click="isVisible = !isVisible"></button>
Обработка событий
<button @click="isVisible = !isVisible">
{{ isVisible ? 'Скрыть' : 'Показать' }}
</button>
<div v-show="isVisible">Содержимое</div>
Показать
Содержимое
Скрыть
Данные между компонентами
{ message: 'Привет!' }
<child></child>parent
child { }
<div></div>
{ message: 'Привет!' }
<child></child>parent
child { }
<div></div>
Как передать?
{ message: 'Привет!' }
<child></child>parent
child
props: { ... }
{ }
<div></div>
Как передать?
props: {
value: null
}
props: {
value: {
required: true,
default: 'foo',
type: String,
validate () {…}
}
}
{ message: 'Привет!' }
<child></child>parent
child
props: { value: null }
{ }
<div></div>
{ message: 'Привет!' }
<child :value="message"></child>parent
child
props: { value: null }
{ }
<div></div>
{ message: 'Привет!' }
<child :value="message"></child>parent
child
props: { value: null }
{ value: 'Привет!' }
<div>Привет!</div>
<child :value="message"></child>
<child :value.once="message"></child>
<child :value.sync="message"></child>
parent (*)→ child
parent (1)→ child
parent ←→ child
●
vue-router, vuex…
●
Slot API
●
DevTools (Hot Reload + TimeTravel)
●
Шикарные доки
А ещё...
Попробуйте Vue.js 1 день
(серьёзно)
Что делать с SEO?
Что делать с SEO?
Хочу видеть контент сразу!
Умеет?
Время
250ms
210ms
430ms
Версия
15.0.2
0.14.8
0.13.3
* В моём личном тесте, NODE_ENV=production
React: SSR
Другие решения
Другие решения
●
Эмуляция (jsdom, PhantomJS)
Другие решения
●
Эмуляция (jsdom, PhantomJS)
●
Snapshots / Prerender.io
Другие решения
●
Эмуляция (jsdom, PhantomJS)
●
Snapshots / Prerender.io [SEO]
VueServer.js
Почему это не сложно?
Почему это не сложно?
●
Vue.js — простой
Почему это не сложно?
●
Vue.js — простой
●
Реактивность — не нужна
Почему это не сложно?
●
Vue.js — простой
●
Реактивность — не нужна
●
Кроссбраузерность — забудьте
Почему это не сложно?
●
Vue.js — простой
●
Реактивность — не нужна
●
Кроссбраузерность — забудьте
●
Не всё писать с нуля
Рендерим.
Как поступить с данными?
Request → State
Request → State
getData()
Request → State
getData()
App
Content
Request → App
Content
Request → App
Content
COMPILED
Request → App
Content
getData()
Request → App
Content
import {renderer} from 'vue-server';
const Vue = new renderer();
new Vue({
template: '<div>Hello world!</div>'
})
import {renderer} from 'vue-server';
const Vue = new renderer();
new Vue({
template: '<div>Hello world!</div>'
})
.$on('vueServer.htmlReady', (html) => {
res.send(html); // '<div>Hello world!</div>'
});
import {compiler} from 'vue-server';
export default {
template: compiler('<div>.../div>')
}
Пре-компиляция шаблонов
npm install gulp-vue-compile
Пре-компиляция шаблонов
Время
430ms
250ms
React@0.13.3
React@15.0.2
* В моём личном тесте
React vs VueServer
Время
430ms
250ms
150ms
React@0.13.3
React@15.0.2
VueServer@0.4.8
* В моём личном тесте
React vs VueServer
Время
30ms
50ms
100ms
Объявление
Главная
Поиск
Рендеринг страниц N1.RU
Серверный → Клиентский HTML
Подходы
●
Подхват (сохранение разметки)
●
Замена (re-rendering)
Пере-рендериваем
Server HTML
head
body
head
body
{{ body }}
head
{{ body }}
body
head
body
body
head
body
body
head
body
body
head
body
body
import {renderer} from 'vue-server';
const Vue = new renderer();
Vue.prototype.$isServer = true;
<span v-if="$isServer">Загрузка...</span>
<select v-else>
...
</select>
VueServer: недостатки
VueServer: недостатки
●
Версия 1.0.0-migration
VueServer: недостатки
●
Версия 1.0.0-migration
●
Свои директивы — нельзя
VueServer: недостатки
●
Версия 1.0.0-migration
●
Свои директивы — нельзя
●
vue-router и другое — не поддерживается
Vue 2.0
Vue 2.0
●
SSR «из коробки»
Vue 2.0
●
SSR «из коробки»
●
API ещё проще (на ~90% совместимо с 1.x)
Vue 2.0
●
SSR «из коробки»
●
API ещё проще (на ~90% совместимо с 1.x)
●
render ()
Спасибо за внимание!
http://n1.ru/
http://vuejs.org/guide/
https://www.npmjs.com/package/vue-server/
https://www.npmjs.com/package/gulp-vue-compile/
Андрей Солодовников
JS-разработчик «НГС Технологии»
a.solodovnikov@office.ngs.ru

Vue.js и его брат-близнец Vue-server.js / Андрей Солодовников (НГС)