diff --git a/LANGS.md b/LANGS.md index 25b60e8a..f379e75a 100644 --- a/LANGS.md +++ b/LANGS.md @@ -1 +1,2 @@ * [English](en/) +* [Русский](ru/) diff --git a/ru/README.md b/ru/README.md new file mode 100644 index 00000000..84d1c08d --- /dev/null +++ b/ru/README.md @@ -0,0 +1,50 @@ +# Руководство по серверному рендерингу Vue.js + +> **Примечание:** для этого руководства требуются следующие версии Vue и библиотек: +> - vue & vue-server-renderer >= 2.3.0 +> - vue-router >= 2.5.0 +> - vue-loader >= 12.0.0 & vue-style-loader >= 3.0.0 + +> Если вы ранее использовали Vue 2.2 с серверным рендерингом, вы заметите, что рекомендуемая структура кода теперь [немного отличается](./structure.md) (с новой опцией [runInNewContext](./api.md#runinnewcontext) установленной в `false`). Ваше существующее приложение по-прежнему будет работать, но советуем внести изменения с учётом новых рекомендаций. + +## Что такое серверный рендеринг (SSR)? + +Vue.js — это фреймворк для создания приложений, выполняемых на клиенте (client-side). По умолчанию компоненты Vue создают и манипулируют DOM в браузере. Однако, также возможно рендерить те же компоненты в HTML-строки на сервере, отправлять их в браузер, и наконец «гидрировать» статическую разметку в полностью интерактивное приложение на клиенте. + +Приложение Vue.js отрендеренное на сервере также можно считать «изоморфным» или «универсальным», в том смысле, что большая часть кода приложения **является общей для сервера и клиента**. + +## Нужен ли вам SSR? + +По сравнению с традиционным SPA (Single-Page Application), преимуществами серверного рендеринга будут: + +- Лучшее SEO, поскольку поисковые роботы будут видеть полностью отрендеренную страницу. + + Обратите внимание, что на данный момент Google and Bing могут без проблем индексировать синхронные приложения JavaScript. Ключевое слово здесь — синхронные. Если ваше приложение запускается с индикатором загрузки, а потом догружает контент через Ajax, то поисковый робот просто не будет дожидаться окончания загрузки. Это значит, что если у вас есть асинхронный контент на страницах где SEO важен, то может потребоваться серверный рендеринг. + +- Лучшие показатели времени до отображения контента (time-to-content), особенно при плохом интернете или на медленных устройствах. Для разметки, отрендеренной на сервере, не требуется дожидаться пока весь JavaScript будет загружен и выполнен, поэтому ваш пользователь увидит полностью отрендеренную страницу раньше. Как правило, это приводит к лучшему пользовательскому опыту и может быть критичным для приложений, где время до отображения контента напрямую связано с коэффициентом конверсии. + +Следует учитывать и некоторые компромиссы при использовании серверного рендеринга: + +- Ограничения при разработке. Код только для браузера может быть использован лишь в определённых хуках жизненного цикла; некоторые внешние библиотеки могут нуждаться в особой обработке, чтобы иметь возможность запускаться в приложении с серверным рендерингом. + +- Более сложные требования по настройке и развёртыванию сборки. В отличие от полностью статичного SPA, который может быть развёрнут на любом статичном файловом сервере, приложение с серверным рендерингом требует окружения, где есть возможность запустить сервер Node.js. + +- Повышенная нагрузка на стороне сервера. Рендеринг полноценного приложения в Node.js очевидно более требователен к ресурсам процессора, чем простая раздача статичных файлов, поэтому если вы ожидаете большой трафик, будьте готовы к соответствующей нагрузке на сервер и используйте стратегии кэширования. + +Прежде чем использовать серверный рендеринг для вашего приложения, задайте себе вопрос, действительно ли он вам нужен. Ответ зависит от того, насколько важно время до контента для вашего приложения. Например, если вы разрабатываете панель мониторинга для внутренних нужд, где дополнительные несколько сотен миллисекунд начальной загрузки не так важны, то серверный рендеринг будет излишеством. Однако, в тех случаях, когда время до контента критично, серверный рендеринг может позволит достичь наилучшей производительности начальной загрузки. + +## SSR vs Пререндеринг + +Если вы интересуетесь серверным рендерингом только для того, чтобы улучшить SEO на нескольких маркетинговых страницах (например, `/`, `/about`, `/contact`, и т.д.), вам скорее всего будет достаточно __пререндеринга__. Вместо того, чтобы заставлять веб-сервер компилировать HTML на лету, пререндеринг просто сгенерирует статичные HTML-файлы для указанных маршрутов на этапе сборки. Преимуществом пререндеринга будет простота реализации, кроме того этот подход позволит вам оставить фронтенд полностью статичным. + +Если вы используете Webpack, то для добавления пререндеринга достаточно установить плагин [prerender-spa-plugin](https://github.com/chrisvfritz/prerender-spa-plugin). Он был тщательно протестирован с приложениями Vue, а его [создатель](https://github.com/chrisvfritz) — член основной команды разработки Vue. + +## Об этом руководстве + +Это руководство ориентировано на SPA приложения с рендерингом на сервере, используя Node.js в качестве сервера. Использование серверного рендеринга Vue совместно с другими технологиями и настройками бэкэнда являются отдельной темой и не рассматриваются в этом руководстве. + +Это руководство будет очень детальным и предполагает, что вы уже знакомы с самим Vue.js, имеете знания и опыт работы с Node.js и Webpack. Если вы предпочитаете более высокоуровневые решения, обеспечивающие работу из коробки — вам следует попробовать [Nuxt.js](http://nuxtjs.org/). Он построен на том же стеке Vue, но позволяет абстрагироваться от написания шаблонного кода, а также предоставляет некоторые дополнительные возможности, такие как генерация статичного сайта. Однако он может не подойти, если вам необходим полный контроль над структурой приложения. В любом случае, вам будет полезно прочитать это руководство, чтобы лучше понимать, как все составляющие работают вместе. + +По мере прочтения руководства, будет полезным обращаться к официальному [демо HackerNews](https://github.com/vuejs/vue-hackernews-2.0/), в котором используется большинство техник, изложенных в этом руководстве. + +Наконец, обратите внимание, что решения в этом руководстве не являются окончательными — мы решили, что они хорошо работают для нас, но это не означает, что они не могут быть улучшены. Они могут быть пересмотрены в будущем — поэтому не стесняйтесь вносить свой вклад, отправляя пулл-реквесты! diff --git a/ru/SUMMARY.md b/ru/SUMMARY.md new file mode 100644 index 00000000..5fb37d1c --- /dev/null +++ b/ru/SUMMARY.md @@ -0,0 +1,27 @@ +- [Использование](basic.md) +- [Написание универсального кода](universal.md) +- [Структура исходного кода](structure.md) +- [Маршрутизация и разделение кода](routing.md) +- [Предзагрузка данных и состояния](data.md) +- [Гидратация клиентской части](hydration.md) +- [Представляем Bundle Renderer](bundle-renderer.md) +- [Конфигурация сборки](build-config.md) +- [Управление CSS](css.md) +- [Управление заголовочными тегами (head)](head.md) +- [Кэширование](caching.md) +- [Стриминг](streaming.md) +- [Справочник API](api.md) + - [createRenderer](api.md#createrendereroptions) + - [createBundleRenderer](api.md#createbundlerendererbundle-options) + - [Класс: Renderer](api.md#class-renderer) + - [Класс: BundleRenderer](api.md#class-bundlerenderer) + - [Опции рендерера](api.md#renderer-options) + - [template](api.md#template) + - [clientManifest](api.md#clientmanifest) + - [inject](api.md#inject) + - [shouldPreload](api.md#shouldpreload) + - [runInNewContext](api.md#runinnewcontext) + - [basedir](api.md#basedir) + - [cache](api.md#cache) + - [directives](api.md#directives) + - [Webpack плагины](api.md#webpack-plugins) diff --git a/ru/api.md b/ru/api.md new file mode 100644 index 00000000..82aea676 --- /dev/null +++ b/ru/api.md @@ -0,0 +1,237 @@ +# Справочник API + +## `createRenderer([options])` + +Создаёт экземпляр [`Renderer`](#class-renderer) с (опциональными) [настройками](#renderer-options). + +``` js +const { createRenderer } = require('vue-server-renderer') +const renderer = createRenderer({ ... }) +``` + +## `createBundleRenderer(bundle[, options])` + +Создаёт экземпляр [`BundleRenderer`](#class-bundlerenderer) с сборкой сервера и (опциональными) [настройками](#renderer-options). + +``` js +const { createBundleRenderer } = require('vue-server-renderer') +const renderer = createBundleRenderer(serverBundle, { ... }) +``` + +Аргумент `serverBundle` может быть одним из следующих: + +- Абсолютный путь к созданному файлу сборки (`.js` или `.json`). Должен начинаться с `/`, чтобы трактоваться как путь к файлу. + +- Объект сборки, сгенерированный Webpack + `vue-server-renderer/server-plugin`. + +- Строка с кодом JavaScript (не рекомендуется). + +См. также [Представляем Bundle Renderer](./bundle-renderer.md) и [Конфигурация сборки](./build-config.md) для подробностей. + +## `Класс: Renderer` + +- #### `renderer.renderToString(vm[, context], callback)` + + Рендерит экземпляр Vue в строку. Объект контекста опционален. Коллбэк является обычным для Node.js коллбэком, где первый аргумент является ошибкой, а второй аргумент — отрендеренной строкой. + +- #### `renderer.renderToStream(vm[, context])` + + Рендерит экземпляр Vue в поток (stream) Node.js. Объект контекста опционален. См. также [Стриминг](./streaming.md) для подробностей. + +## `Класс: BundleRenderer` + +- #### `bundleRenderer.renderToString([context, ]callback)` + + Рендерит сборку в строку. Объект контекста опционален. Коллбэк является обычным для Node.js коллбэком, где первый аргумент является ошибкой, а второй аргумент — отрендеренной строкой. + +- #### `bundleRenderer.renderToStream([context])` + + Рендерит сборку в поток (stream) Node.js. Объект контекста опционален. См. также [Стриминг](./streaming.md) для подробностей. + +## Настройки рендерера + +- #### `template` + + Предоставляет шаблон для всей HTML-страницы. Шаблон должен содержать комментарий ``, который определяет место подстановки отрендеренного контента приложения. + + Шаблон также поддерживает базовые интерполяции с использованием контекста рендера: + + - Используйте двойные фигурные скобки для интерполяции экранированного HTML; + - Используйте тройные фигурные скобки для интерполяции сырого HTML. + + Шаблон автоматически внедряет соответствующий контент, когда определённые свойства найдены в контексте рендера: + + - `context.head`: (string) любая разметка для head, которая должна быть вставлена в заголовочный тег страницы. + + - `context.styles`: (string) любой встроенный CSS, который должен быть вставлен в заголовочный тег страницы. Обратите внимание, что это свойство будет автоматически заполнено при использовании `vue-loader` + `vue-style-loader` для CSS компонента. + + - `context.state`: (Object) начальное состояние хранилища Vuex, которое должно быть внедрено в страницу как `window.__INITIAL_STATE__`. Внедряемый JSON автоматически обрабатывается с помощью [serialize-javascript](https://github.com/yahoo/serialize-javascript) для предотвращения XSS-уязвимостей. + + Кроме того, когда предоставлен `clientManifest`, шаблон автоматически внедряет следующее: + + - JavaScript и CSS ресурсы для клиентской части, необходимые для рендеринга (с асинхронными фрагментами добавляемыми автоматически); + - Оптимальные ресурсы `` для отображаемой страницы. + + Вы можете отключить все автоматические внедрения передав `inject: false` в рендерер. + + См. также: + + - [Использование шаблона страниц](./basic.md#using-a-page-template) + - [Внедрение ресурсов вручную](./build-config.md#manual-asset-injection) + +- #### `clientManifest` + + - 2.3.0+ + - используется только в `createBundleRenderer` + + Предоставляет объект манифеста клиентской сборки, сгенерированный `vue-server-renderer/server-plugin`. Клиентский манифест предоставляет для рендерера сборки необходимую информацию для автоматического внедрения ресурсов в шаблон HTML. Подробнее в разделе [Генерация `clientManifest`](./build-config.md#generating-clientmanifest). + +- #### `inject` + + - 2.3.0+ + + Контролирует, выполнять ли автоматические внедрения при использовании `template`. По умолчанию `true`. + + См. также: [Внедрение ресурсов вручную](./build-config.md#manual-asset-injection). + +- #### `shouldPreload` + + - 2.3.0+ + + Функция, определяющая какие файлы должны иметь `` в генерируемых ресурсах. + + По умолчанию, только JavaScript и CSS файлы будут предзагружаться, так как они абсолютно необходимы для загрузки приложения. + + Для других типов ресурсов, таких как изображения или шрифты, предзагрузка может привести к ненужному увеличению объёмов передаваемой информации и даже к ухудшению производительности, поэтому список файлов, которые нужно предзагружать, зависит от ситуации. Вы можете точно контролировать, что требует предзагрузки, используя опцию `shouldPreload`: + + ``` js + const renderer = createBundleRenderer(bundle, { + template, + clientManifest, + shouldPreload: (file, type) => { + // тип определяется на основе расширения файла. + // https://fetch.spec.whatwg.org/#concept-request-destination + if (type === 'script' || type === 'style') { + return true + } + if (type === 'font') { + // предзагружать только woff2 шрифты + return /\.woff2$/.test(file) + } + if (type === 'image') { + // предзагружать только важные изображения + return file === 'hero.jpg' + } + } + }) + ``` + +- #### `runInNewContext` + + - 2.3.0+ + - используется только в `createBundleRenderer` + - Ожидается: `boolean | 'once'` (`'once'` поддерживается только с версии 2.3.1+) + + По умолчанию, рендерер сборки будет создавать новый контекст V8 для каждого рендеринга и повторно исполнять всю сборку. Это имеет некоторые преимущества — например, код приложения изолирован от процесса сервера и не нужно беспокоиться [о проблеме «синглетона с состоянием»](./structure.md#avoid-stateful-singletons), которая упоминалась ранее в руководстве. Однако этот режим требует значительных затрат производительности, поскольку повторное выполнение сборки обходится дорого, особенно когда приложение становится большим. + + По умолчанию эта опция имеет значение `true` для обеспечения обратной совместимости, но рекомендуется использовать `runInNewContext: false` или `runInNewContext: 'once'` всегда, когда это возможно. + + > В версии 2.3.0 у этой опции есть ошибка, когда при `runInNewContext: false` сборка всё ещё исполнялась в отдельном глобальном контексте. Информация далее предполагает использование версии 2.3.1+. + + С опцией `runInNewContext: false`, код сборки будет выполняться в том же контексте `global`, что и серверный процесс, поэтому нужно быть осторожным с кодом, который изменяет `global` в вашем приложении. + + С опцией `runInNewContext: 'once'` (добавлено в версии 2.3.1+), сборка выполняется в отдельном контексте `global`, но только один раз при запуске. Это обеспечивает лучшую изоляцию кода приложения поскольку предотвращает случайно загрязнение объекта `global` серверного процесса. Предостережения заключаются в следующем: + + 1. Зависимости, которые изменяют `global` (например, полифиллы) не должны быть объявлены внешними зависимостями в этом режиме; + 2. Значения, возвращаемые при выполнении сборки будут использовать разные глобальные конструкторы, например, ошибка внутри сборки не будет экземпляром `Error` в серверном процессе. + + См. также: [Структура исходного кода](./structure.md) + +- #### `basedir` + + - 2.2.0+ + - используется только в `createBundleRenderer` + + Указание пути базового каталога для серверной сборки для разрешения зависимостей из `node_modules` в нём. Это необходимо только в том случае, если сгенерированный файл сборки располагается в другом месте, в отличии от используемых NPM-зависимостей, или когда ваш `vue-server-renderer` подключен NPM-ссылкой в вашем текущем проекте. + +- #### `cache` + + Реализация [кэширования на уровне компонентов](./caching.md#component-level-caching). Объект кэша должен реализовать следующий интерфейс (соответствуя нотациям Flow): + + ``` js + type RenderCache = { + get: (key: string, cb?: Function) => string | void; + set: (key: string, val: string) => void; + has?: (key: string, cb?: Function) => boolean | void; + }; + ``` + + Для обычного использования достаточно передать [lru-cache](https://github.com/isaacs/node-lru-cache): + + ``` js + const LRU = require('lru-cache') + + const renderer = createRenderer({ + cache: LRU({ + max: 10000 + }) + }) + ``` + + Обратите внимание, что объект кэша по крайне мере должен реализовывать `get` и `set`. Кроме того, `get` и `has` опционально могут быть асинхронными, если они принимают второй аргумент как коллбэк. Это позволяет кэшу использовать асинхронные API, например для Redis: + + ``` js + const renderer = createRenderer({ + cache: { + get: (key, cb) => { + redisClient.get(key, (err, res) => { + // обработка ошибок, если таковые будут + cb(res) + }) + }, + set: (key, val) => { + redisClient.set(key, val) + } + } + }) + ``` + +- #### `directives` + + Позволяет предоставить серверную реализацию для ваших пользовательских директив: + + ``` js + const renderer = createRenderer({ + directives: { + example (vnode, directiveMeta) { + // преобразуем vnode на основе метаданных привязанных к директиве + } + } + }) + ``` + + Например, можете посмотреть [серверную реализацию для директивы `v-show`](https://github.com/vuejs/vue/blob/dev/src/platforms/web/server/directives/show.js). + +## Webpack плагины + +Webpack плагины предоставляются как отдельные файлы, которые должны быть подключены напрямую: + +``` js +const VueSSRServerPlugin = require('vue-server-renderer/server-plugin') +const VueSSRClientPlugin = require('vue-server-renderer/client-plugin') +``` + +По умолчанию генерируются файлы: + +- `vue-ssr-server-bundle.json` для серверной сборки; +- `vue-ssr-client-manifest.json` для клиентской сборки. + +Имена файлов могут быть изменены при создании экземпляров плагина: + +``` js +const plugin = new VueSSRServerPlugin({ + filename: 'my-server-bundle.json' +}) +``` + +См. также [Конфигурация сборки](./build-config.md) для подробной информации. diff --git a/ru/basic.md b/ru/basic.md new file mode 100644 index 00000000..cac87f2e --- /dev/null +++ b/ru/basic.md @@ -0,0 +1,147 @@ +# Использование + +## Установка + +``` bash +npm install vue vue-server-renderer --save +``` + +В руководстве мы будем использовать NPM, но вы свободно можете использовать и [Yarn](https://yarnpkg.com/en/). + +#### Примечания + +- Рекомендуется использовать Node.js версии 6+. +- `vue-server-renderer` и `vue` должны иметь одинаковые версии. +- `vue-server-renderer` зависит от некоторых нативных модулей Node.js и поэтому может использоваться только в Node.js. Возможно в будущем мы предоставим более простую сборку, которая сможет быть запущена в других средах исполнения JavaScript. + +## Рендеринг экземпляра Vue + +``` js +// Шаг 1: Создаём экземпляр Vue +const Vue = require('vue') +const app = new Vue({ + template: `
Hello World
` +}) + +// Шаг 2: Создаём рендерер +const renderer = require('vue-server-renderer').createRenderer() + +// Шаг 3: Рендерим экземпляр Vue в HTML +renderer.renderToString(app, (err, html) => { + if (err) throw err + console.log(html) + // =>
hello world
+}) +``` + +## Интеграция с сервером + +Это достаточно просто когда мы используем сервер на Node.js, например [Express](https://expressjs.com/): + +``` bash +npm install express --save +``` +--- +``` js +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: `
Вы открыли URL: {{ url }}
` + }) + + renderer.renderToString(app, (err, html) => { + if (err) { + res.status(500).end('Внутренняя ошибка сервера') + return + } + res.end(` + + + Привет + ${html} + + `) + }) +}) + +server.listen(8080) +``` + +## Использование шаблона страниц + +Когда вы рендерите приложение Vue, рендерер генерирует только разметку приложения. В примере выше нам потребовалось обернуть вывод дополнительным кодом для создания обычной HTML-страницы. + +Вы можете упростить это, предоставив шаблон страницы при создании рендерера. Чаще всего нам требуется расположить шаблон в отдельном файле, например `index.template.html`: + +``` html + + + Привет + + + + +``` + +Обратите внимание на комментарий `` — сюда будет подставлена разметка вашего приложения. + +Теперь мы можем прочитать этот файл и передать его в рендерер Vue: + +``` js +const renderer = createRenderer({ + template: require('fs').readFileSync('./index.template.html', 'utf-8') +}) + +renderer.renderToString(app, (err, html) => { + console.log(html) // будет выведен код всей страницы, с подставленным кодом приложения. +}) +``` + +### Интерполяции в шаблоне + +Шаблон поддерживает простые интерполяции. Например: + +``` html + + + {{ title }} + {{{ meta }}} + + + + + +``` + +Мы можем предоставить необходимые данные для интерполяции, передав объект контекста для рендера вторым аргументом в `renderToString`: + +``` js +const context = { + title: 'привет', + meta: ` + + + ` +} + +renderer.renderToString(app, context, (err, html) => { + // заголовок страницы будет "привет" + // meta-теги также будут подставлены в код страницы +}) +``` + +Объект `context` может также использоваться совместно с экземпляром Vue приложения, что разрешает компонентам динамически регистрировать данные для интерполяции в шаблоне. + +Кроме того, шаблон поддерживает некоторые продвинутые функции: + +- Автоматическую подстановку критически важного CSS при использовании `*.vue` компонентов; +- Автоматическую подстановку ссылок и подсказок для ресурсов (preload / prefetch) при использовании `clientManifest`; +- Автоматическую подстановку и предотвращение XSS при встраивании Vuex-состояния для гидратации на стороне клиента. + +Мы обсудим это дальше, когда будем разбирать все связанные концепции. diff --git a/ru/build-config.md b/ru/build-config.md new file mode 100644 index 00000000..4f8bbcec --- /dev/null +++ b/ru/build-config.md @@ -0,0 +1,215 @@ +# Конфигурация сборки + +Мы предполагаем, что вы уже знаете как настраивать Webpack для клиентской части проектов. Конфигурация для проекта SSR будет во многом схожей, но мы предлагаем разбивать конфигурацию на три файла: *base*, *client* и *server*. Базовая конфигурация (base) содержит конфигурацию, совместно используемую для обоих окружений, такие как пути вывода, псевдонимы и загрузчики. Конфигурация сервера (server) и конфигурация клиента (client) просто расширяют базовую конфигурацию, используя [webpack-merge](https://github.com/survivejs/webpack-merge). + +## Конфигурация серверной части + +Конфигурация серверной части предназначена для создания серверной сборки, которая будет передана в `createBundleRenderer`. Это должно выглядеть так: + +``` js +const merge = require('webpack-merge') +const nodeExternals = require('webpack-node-externals') +const baseConfig = require('./webpack.base.config.js') +const VueSSRServerPlugin = require('vue-server-renderer/server-plugin') + +module.exports = merge(baseConfig, { + // Укажите точку входа серверной части вашего приложения + entry: '/path/to/entry-server.js', + + // Это позволяет Webpack обрабатывать динамические импорты в Node-стиле, + // а также сообщает `vue-loader` генерировать серверно-ориентированный код + // при компиляции компонентов Vue. + target: 'node', + + // Для поддержки source map в bundle renderer + devtool: 'source-map', + + // Это сообщает что в серверной сборке следует использовать экспорты в стиле Node + output: { + libraryTarget: 'commonjs2' + }, + + // https://webpack.js.org/configuration/externals/#function + // https://github.com/liady/webpack-node-externals + // Внешние зависимости приложения. Это значительно ускоряет процесс + // сборки серверной части и уменьшает размер итогового файла сборки. + externals: nodeExternals({ + // не выделяйте зависимости, которые должны обрабатываться Webpack. + // здесь вы можете добавить больше типов файлов, например сырые *.vue файлы + // нужно также указывать белый список зависимостей изменяющих `global` (например, полифиллы) + whitelist: /\.css$/ + }), + + // Этот плагин преобразует весь результат серверной сборки + // в один JSON-файл. Имя по умолчанию будет + // `vue-ssr-server-bundle.json` + plugins: [ + new VueSSRServerPlugin() + ] +}) +``` + +После создания `vue-ssr-server-bundle.json` просто передайте путь к файлу в `createBundleRenderer`: + +``` js +const { createBundleRenderer } = require('vue-server-renderer') +const renderer = createBundleRenderer('/path/to/vue-ssr-server-bundle.json', { + // ...другие настройки рендерера +}) +``` + +В качестве альтернативы, вы также можете передать сборку как объект в `createBundleRenderer`. Это полезно для горячей перезагрузки во время разработки — см. демо HackerNews для [примера настройки](https://github.com/vuejs/vue-hackernews-2.0/blob/master/build/setup-dev-server.js). + +### Ограничения externals + +Обратите внимание, что в параметре `externals` мы указываем белый список CSS файлов. Это связано с тем, что CSS, импортированный из зависимостей всё равно должен быть обработан Webpack. Если вы импортируете любые другие типы файлов, которые также полагаются на Webpack (например, `*.vue`, `*.sass`), вы должны их также добавить в белый список. + +Если вы используете `runInNewContext: 'once'` или `runInNewContext: true`, вам также требуется добавить в белый список являются полифиллы, которые изменяют `global`, например `babel-polyfill`. Это связано с тем, что при использовании режима нового контекста, **код внутри серверной сборки имеет свой собственный объект `global`**. Поскольку это не будет нужно на сервере при использовании Node 7.6+, на самом деле проще просто импортировать его в клиентской точке входа. + +## Конфигурация клиентской части + +Конфигурация клиентской части может оставаться практически такой же, как и базовой. Очевидно, вам нужно указать `entry` на файл входной точки клиентской части. Кроме того, если вы используете `CommonsChunkPlugin`, убедитесь, что используете его только в конфигурации клиентской части, потому что для серверной сборки требуется одна точка входа. + +### Генерация `clientManifest` + +> требуется версия 2.3.0+ + +Помимо серверной сборки, мы также можем сгенерировать манифест сборки. С помощью манифеста клиентской части и серверной сборки, у рендерера появится информация о серверной *и* клиентской сборке, поэтому он может автоматически внедрять [директивы preload/prefetch](https://css-tricks.com/prefetching-preloading-prebrowsing/) в ссылки на CSS / теги script в отображаемом HTML. + +Выгода тут двойная: + +1. Он может заменить `html-webpack-plugin` для внедрения правильных URL-адресов ресурсов, когда в генерируемых именах файлов есть хэши. + +2. При рендеринге сборки, которая использует возможности разделения кода Webpack, мы можем гарантировать, что оптимальные части были предзагружены и предзаполнены, а также интеллектуально внедрять теги ` + + + + +` +``` + +### Внедрение ресурсов вручную + +По умолчанию, внедрение ресурсов выполняется автоматически при использовании опции `template` для рендера. Но иногда вам может понадобиться больше контроля над тем, как ресурсы должны внедряться в шаблон, или, возможно, вы не используете шаблон вообще. В таком случае вы можете передать опцию `inject: false` при создании рендерера и производить внедрение ресурсов вручную. + +В коллбэке `renderToString` объект `context`, который вы передали, предоставляет следующие методы: + +- `context.renderStyles()` + + Возвращает встроенные теги `