Начало работы
Установка
npm install vue vue-server-renderer --save
В руководстве мы будем использовать NPM, но вы свободно можете использовать и Yarn (opens new window).
Примечания
- Рекомендуется использовать Node.js версии 10+.
vue-server-renderer
иvue
должны иметь одинаковые версии.vue-server-renderer
зависит от некоторых нативных модулей Node.js и поэтому может использоваться только в Node.js. Возможно в будущем мы предоставим более простую сборку, которая сможет быть запущена в других средах исполнения JavaScript.
Рендеринг экземпляра Vue
// Шаг 1: Создаём экземпляр Vue
const Vue = require('vue')
const app = new Vue({
template: `<div>Hello World</div>`
})
// Шаг 2: Создаём рендерер
const renderer = require('vue-server-renderer').createRenderer()
// Шаг 3: Рендерим экземпляр Vue в HTML
renderer.renderToString(app, (err, html) => {
if (err) throw err
console.log(html)
// => <div data-server-rendered="true">Hello World</div>
})
// с версии 2.5.0+, возвращает Promise если коллбэк не указан:
renderer.renderToString(app).then(html => {
console.log(html)
}).catch(err => {
console.error(err)
})
Интеграция с сервером
Это достаточно просто когда мы используем сервер на Node.js, например Express (opens new window):
npm install express --save
const Vue = require('vue')
const server = require('express')()
const renderer = require('vue-server-renderer').createRenderer()
server.get('*', (req, res) => {
const app = new Vue({
data: {
url: req.url
},
template: `<div>Вы открыли URL: {{ url }}</div>`
})
renderer.renderToString(app, (err, html) => {
if (err) {
res.status(500).end('Внутренняя ошибка сервера')
return
}
res.end(`
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<head><title>Привет</title></head>
<body>${html}</body>
</html>
`)
})
})
server.listen(8080)
Использование шаблона страниц
Когда вы рендерите приложение Vue, рендерер генерирует только разметку приложения. В примере выше нам потребовалось обернуть вывод дополнительным кодом для создания обычной HTML-страницы.
Вы можете упростить это, предоставив шаблон страницы при создании рендерера. Чаще всего нам требуется расположить шаблон в отдельном файле, например index.template.html
:
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<head><title>Привет</title></head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
Обратите внимание на комментарий <!--vue-ssr-outlet-->
— сюда будет подставлена разметка вашего приложения.
Теперь мы можем прочитать этот файл и передать его в рендерер Vue:
const renderer = require('vue-server-renderer').createRenderer({
template: require('fs').readFileSync('./index.template.html', 'utf-8')
})
renderer.renderToString(app, (err, html) => {
console.log(html) // выведется код всей страницы, с подставленным кодом приложения.
})
Интерполяции в шаблоне
Шаблон поддерживает простые интерполяции. Например:
<html>
<head>
<!-- Используйте двойные фигурные скобки для экранированного HTML-кода -->
<title>{{ title }}</title>
<!-- Используйте тройные фигурные скобки для подстановки сырого HTML -->
{{{ meta }}}
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
Мы можем предоставить необходимые данные для интерполяции, передав объект контекста для рендера вторым аргументом в renderToString
:
const context = {
title: 'привет',
meta: `
<meta ...>
<meta ...>
`
}
renderer.renderToString(app, context, (err, html) => {
// заголовок страницы будет "привет"
// meta-теги также будут подставлены в код страницы
})
Объект context
может также использоваться совместно с экземпляром Vue приложения, что разрешает компонентам динамически регистрировать данные для интерполяции в шаблоне.
Кроме того, шаблон поддерживает некоторые продвинутые функции:
- Автоматическую подстановку критически важного CSS при использовании
*.vue
компонентов; - Автоматическую подстановку ссылок и подсказок для ресурсов (preload / prefetch) при использовании
clientManifest
; - Автоматическую подстановку и предотвращение XSS при встраивании Vuex-состояния для гидратации на стороне клиента.
Мы обсудим это дальше, когда будем разбирать все связанные концепции.
Полный листинг кода для демо
const Vue = require('vue');
const server = require('express')();
const template = require('fs').readFileSync('./index.template.html', 'utf-8');
const renderer = require('vue-server-renderer').createRenderer({
template,
});
const context = {
title: 'vue ssr',
meta: `
<meta charset="utf-8" />
<meta name="keyword" content="vue,ssr">
<meta name="description" content="vue ssr demo">
`,
};
server.get('*', (req, res) => {
const app = new Vue({
data: {
url: req.url
},
template: `<div>Вы открыли URL: {{ url }}</div>`,
});
renderer
.renderToString(app, context, (err, html) => {
console.log(html);
if (err) {
res.status(500).end('Internal Server Error')
return;
}
res.end(html);
});
})
server.listen(8080);