From bfd61909b0b1d46c359a6b35799d78919f069109 Mon Sep 17 00:00:00 2001 From: Alex Sokolov Date: Mon, 22 May 2017 09:04:57 +0300 Subject: [PATCH 01/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=B1=D1=8D=D0=BA=D1=82=D0=B8=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ru/data.md | 6 +++--- ru/structure.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ru/data.md b/ru/data.md index 809b78d6..b49f1524 100644 --- a/ru/data.md +++ b/ru/data.md @@ -28,7 +28,7 @@ export function createStore () { }, actions: { fetchItem ({ commit }, id) { - // возвращаем Promise через store.dispatch() + // возвращаем Promise через `store.dispatch()` // чтобы мы могли понять когда данные будут загружены return fetchItem(id).then(item => { commit('setItem', { id, item }) @@ -125,7 +125,7 @@ export default context => { reject({ code: 404 }) } - // вызов asyncData() на всех соответствующих компонентах + // вызов `asyncData()` на всех соответствующих компонентах Promise.all(matchedComponents.map(Component => { if (Component.asyncData) { return Component.asyncData({ @@ -179,7 +179,7 @@ if (window.__INITIAL_STATE__) { // Добавляем хук маршрута для обработки asyncData. // Выполняем его после разрешения первоначального маршрута, // чтобы дважды не загружать данные, которые у нас уже есть. - // Используем router.beforeResolve(), чтобы все асинхронные компоненты были разрешены. + // Используем `router.beforeResolve()`, чтобы все асинхронные компоненты были разрешены. router.beforeResolve((to, from, next) => { const matched = router.getMatchedComponents(to) const prevMatched = router.getMatchedComponents(from) diff --git a/ru/structure.md b/ru/structure.md index 20f78fd6..93438fe2 100644 --- a/ru/structure.md +++ b/ru/structure.md @@ -105,7 +105,7 @@ import { createApp } from './app' const { app } = createApp() -// предполагается, что у корневого элемента в шаблоне App.vue есть элемент с id="app" +// предполагается, что у корневого элемента в шаблоне App.vue есть элемент с `id="app"` app.$mount('#app') ``` From 63a36737684be1d8189987dda763e00ca48b27cf Mon Sep 17 00:00:00 2001 From: Alex Sokolov Date: Mon, 22 May 2017 14:44:08 +0300 Subject: [PATCH 02/11] =?UTF-8?q?routing.md=20=D0=B8=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5?= =?UTF-8?q?=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ru/routing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ru/routing.md b/ru/routing.md index f0d4f980..a229384b 100644 --- a/ru/routing.md +++ b/ru/routing.md @@ -67,7 +67,7 @@ export default context => { const matchedComponents = router.getMatchedComponents() // нет подходящих маршрутов, отклоняем с 404 if (!matchedComponents.length) { - reject({ code: 404 }) + return reject({ code: 404 }) } // Promise должен разрешиться экземпляром приложения, который будет отрендерен From 5b07856b1deaf3f8e7a3e05430495ae15976d534 Mon Sep 17 00:00:00 2001 From: Alex Sokolov Date: Mon, 22 May 2017 15:09:28 +0300 Subject: [PATCH 03/11] =?UTF-8?q?data.md=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ru/data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ru/data.md b/ru/data.md index b49f1524..06ab5366 100644 --- a/ru/data.md +++ b/ru/data.md @@ -122,7 +122,7 @@ export default context => { router.onReady(() => { const matchedComponents = router.getMatchedComponents() if (!matchedComponents.length) { - reject({ code: 404 }) + return reject({ code: 404 }) } // вызов `asyncData()` на всех соответствующих компонентах From dfba0d6f58d7c64c26a014c5f540a535b473a29a Mon Sep 17 00:00:00 2001 From: Alex-Sokolov Date: Sat, 27 May 2017 14:27:47 +0300 Subject: [PATCH 04/11] =?UTF-8?q?data.md=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=B1=D1=8D=D0=BA=D1=82=D0=B8=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ru/data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ru/data.md b/ru/data.md index 06ab5366..f2491663 100644 --- a/ru/data.md +++ b/ru/data.md @@ -138,7 +138,7 @@ export default context => { // заполнено состоянием, необходимым для рендеринга приложения. // Когда мы присоединяем состояние к контексту, и есть опция `template` // используемая для рендерера, состояние будет автоматически - // сериализовано и внедрено в HTML как window.__INITIAL_STATE__. + // сериализовано и внедрено в HTML как `window.__INITIAL_STATE__`. context.state = store.state resolve(app) From d9df311e02c90e9635787cc89021b1eaed6363b4 Mon Sep 17 00:00:00 2001 From: Alex Sokolov Date: Tue, 27 Jun 2017 14:59:48 +0300 Subject: [PATCH 05/11] =?UTF-8?q?data.md=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ru/data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ru/data.md b/ru/data.md index f2491663..72971abf 100644 --- a/ru/data.md +++ b/ru/data.md @@ -215,7 +215,7 @@ if (window.__INITIAL_STATE__) { 2. **Загружать данные после отображения нового представления:** - Эта стратегия располагает логику загрузки данных на стороне клиента в функции компонента `beforeMount`. Это позволяет переключаться мгновенно при срабатывании навигации по маршруту, поэтому приложение ощущается более отзывчивым. Однако на момент отображения нового представления у него не будет полных данных. Поэтому необходимо иметь добавлять условие проверки загруженности состояния для каждого компонента, использующего эту стратегию. + Эта стратегия располагает логику загрузки данных на стороне клиента в функции компонента `beforeMount`. Это позволяет переключаться мгновенно при срабатывании навигации по маршруту, поэтому приложение ощущается более отзывчивым. Однако на момент отображения нового представления у него не будет полных данных. Поэтому необходимо добавлять условие проверки загруженности состояния для каждого компонента, использующего эту стратегию. Этого можно достичь с помощью глобальной примеси на клиенте: From ec41ef31756f6ef48839de3d196e73fd6d865a69 Mon Sep 17 00:00:00 2001 From: Alex Sokolov Date: Fri, 30 Jun 2017 08:56:32 +0300 Subject: [PATCH 06/11] =?UTF-8?q?universal.md=20=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ru/universal.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ru/universal.md b/ru/universal.md index 60179795..45436633 100644 --- a/ru/universal.md +++ b/ru/universal.md @@ -1,6 +1,6 @@ # Написание универсального кода -Прежде чем идти дальше, давайте немного обсудим ограничения при написании «универсального» кода — кода, который выполняется как на сервере, так и на клиенте. Из-за различий в API платформы, поведение нашего кода будет отличаться при работе в разных средах выполнения. Здесь мы рассмотрим ключевые моменты, которые нужно вам нужно знать. +Прежде чем идти дальше, давайте немного обсудим ограничения при написании «универсального» кода — кода, который выполняется как на сервере, так и на клиенте. Из-за различий в API платформы, поведение нашего кода будет отличаться при работе в разных средах выполнения. Здесь мы рассмотрим ключевые моменты, которые вам нужно знать. ## Реактивность данных на сервере From fa8c52a4f1664c5314facb081bde58ae02317e5f Mon Sep 17 00:00:00 2001 From: Alex Sokolov Date: Fri, 30 Jun 2017 09:08:16 +0300 Subject: [PATCH 07/11] =?UTF-8?q?universal.md=20=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ru/universal.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ru/universal.md b/ru/universal.md index 45436633..0bf7151c 100644 --- a/ru/universal.md +++ b/ru/universal.md @@ -22,7 +22,7 @@ Для API только для браузеров общий подход — ленивый (lazy) доступ к ним, внутри хуков жизненного цикла только для клиентской стороны. -Обратите внимание, что если сторонняя библиотека не была написана с расчётом на универсальное использование, её может быть сложно интегрировать в приложение с серверным рендерингом. Вы *могли бы* заставить её работать, например создавая моки некоторых глобальных переменных, но это будет грязным хаком и может помешать коду обнаружения окружения в других библиотеках. +Обратите внимание, если сторонняя библиотека не была написана с расчётом на универсальное использование, её может быть сложно интегрировать в приложение с серверным рендерингом. Вы *могли бы* заставить её работать, например создавая моки некоторых глобальных переменных, но это будет грязным хаком и может помешать коду обнаружения окружения в других библиотеках. ## Пользовательские директивы From 568204173242605afa2fa6b149272d86e386e5d3 Mon Sep 17 00:00:00 2001 From: Alex-Sokolov Date: Thu, 20 Jul 2017 22:18:31 +0300 Subject: [PATCH 08/11] =?UTF-8?q?api.md=20=D0=BE=D0=BF=D0=B5=D1=87=D0=B0?= =?UTF-8?q?=D1=82=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ru/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ru/api.md b/ru/api.md index 43e6c079..05de5a5c 100644 --- a/ru/api.md +++ b/ru/api.md @@ -131,7 +131,7 @@ const renderer = createBundleRenderer(serverBundle, { ... }) - используется только в `createBundleRenderer` - Ожидается: `boolean | 'once'` (`'once'` поддерживается только с версии 2.3.1+) - По умолчанию, рендерер сборки будет создавать новый контекст V8 для каждого рендеринга и повторно исполнять всю сборку. Это имеет некоторые преимущества — например, код приложения изолирован от процесса сервера и не нужно беспокоиться [о проблеме «синглетона с состоянием»](./structure.md#avoid-stateful-singletons), которая упоминалась ранее в руководстве. Однако этот режим требует значительных затрат производительности, поскольку повторное выполнение сборки обходится дорого, особенно когда приложение становится большим. + По умолчанию, рендерер сборки будет создавать новый контекст V8 для каждого рендеринга и повторно исполнять всю сборку. Это имеет некоторые преимущества — например, код приложения изолирован от процесса сервера и не нужно беспокоиться [о проблеме «синглтона с состоянием»](./structure.md#avoid-stateful-singletons), которая упоминалась ранее в руководстве. Однако этот режим требует значительных затрат производительности, поскольку повторное выполнение сборки обходится дорого, особенно когда приложение становится большим. По умолчанию эта опция имеет значение `true` для обеспечения обратной совместимости, но рекомендуется использовать `runInNewContext: false` или `runInNewContext: 'once'` всегда, когда это возможно. From 3d7ef5cae3cbcfeefc3167d997b763d5010e3f33 Mon Sep 17 00:00:00 2001 From: Alex-Sokolov Date: Thu, 20 Jul 2017 22:18:39 +0300 Subject: [PATCH 09/11] =?UTF-8?q?structure.md=20=D0=BE=D0=BF=D0=B5=D1=87?= =?UTF-8?q?=D0=B0=D1=82=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ru/structure.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ru/structure.md b/ru/structure.md index 93438fe2..e7be6e22 100644 --- a/ru/structure.md +++ b/ru/structure.md @@ -1,8 +1,8 @@ # Структура исходного кода -## Избегайте синглетонов с состоянием +## Избегайте синглтонов с состоянием -При написании кода для клиентской стороны мы привыкли к тому, что наш код каждый раз будет выполняться в новом контексте. Однако сервер Node.js является длительным процессом (long-running process). Поэтому когда наш код потребуется, он будет выполнен один раз и останется в памяти. Это означает, что если вы создаёте объект синглетон, он будет использоваться для всех входящих запросов. +При написании кода для клиентской стороны мы привыкли к тому, что наш код каждый раз будет выполняться в новом контексте. Однако сервер Node.js является длительным процессом (long-running process). Поэтому когда наш код потребуется, он будет выполнен один раз и останется в памяти. Это означает, что если вы создаёте объект синглтон, он будет использоваться для всех входящих запросов. Как видно из простого примера, мы **создаём новый корневой экземпляр Vue для каждого запроса**. Это схоже с тем, когда каждый пользователь будет использовать свежий экземпляр приложения в своём браузере. Если мы будем использовать общий экземпляр для нескольких запросов, то это быстро приведёт к загрязнению состояния. From 9526759606e079ecbcb28d83c6bc1639168d8ddf Mon Sep 17 00:00:00 2001 From: Alex Sokolov Date: Thu, 7 Sep 2017 09:41:25 +0300 Subject: [PATCH 10/11] =?UTF-8?q?=D0=9C=D0=B5=D0=BB=D0=BA=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8,=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D1=81=D0=B8=D0=B9=20=D0=BA=20=D0=B5=D0=B4=D0=B8=D0=BD=D0=BE?= =?UTF-8?q?=D0=BC=D1=83=20=D0=B2=D0=B8=D0=B4=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ru/README.md | 6 +++--- ru/caching.md | 4 ++-- ru/css.md | 2 +- ru/head.md | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ru/README.md b/ru/README.md index 84d1c08d..1bd6b71d 100644 --- a/ru/README.md +++ b/ru/README.md @@ -1,9 +1,9 @@ # Руководство по серверному рендерингу 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 & 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`). Ваше существующее приложение по-прежнему будет работать, но советуем внести изменения с учётом новых рекомендаций. diff --git a/ru/caching.md b/ru/caching.md index 01fd13cc..4824918a 100644 --- a/ru/caching.md +++ b/ru/caching.md @@ -6,7 +6,7 @@ Приложение с рендерингом на стороне сервера в большинстве случаев зависит от внешних данных, поэтому содержимое является динамическим, по своей природе, и не может кэшироваться в течение длительных периодов времени. Однако, если содержимое не зависит от конкретного пользователя (например, для одного и того же URL всегда отображается одинаковое содержимое всем пользователям), мы можем использовать стратегию под названием [микро-кэширование](https://www.nginx.com/blog/benefits-of-microcaching-nginx/), чтобы значительно улучшить возможности нашего приложения для обработки большого трафика. -Это обычно реализуется на уровне Nginx, но мы также можем реализовать его в Node.js: +Это обычно реализуется на уровне nginx, но мы также можем реализовать его в Node.js: ``` js const microCache = LRU({ @@ -67,7 +67,7 @@ export default { } ``` -Обратите внимание, что подлежащий кэшированию компонент **также должен определять уникальную опцию «name»**. С уникальным именем ключ кэша таким образом является компоненто-зависимым: вам не нужно беспокоиться о двух компонентах, возвращающих одинаковый ключ. +Обратите внимание, что подлежащий кэшированию компонент **также должен определять уникальную опцию `name`**. С уникальным именем ключ кэша таким образом является компоненто-зависимым: вам не нужно беспокоиться о двух компонентах, возвращающих одинаковый ключ. Ключ, возвращаемый из `serverCacheKey` должен содержать достаточную информацию для представления формы результата рендеринга. Указанное выше является хорошей реализацией, если результат рендеринга определяется исключительно с помощью `props.item.id`. Однако, если элемент с таким же идентификатором может со временем меняться или результат рендеринга также зависит от других данных, вам необходимо изменить реализацию `getCacheKey`, чтобы учитывать и другие переменные. diff --git a/ru/css.md b/ru/css.md index 5db5a412..64d142bd 100644 --- a/ru/css.md +++ b/ru/css.md @@ -22,7 +22,7 @@ ## Настройка извлечения CSS -Для извлечения CSS из `*.vue` файлов в `vue-loader` используется опция `extractCSS` (требует `vue-loader>=12.0.0`): +Для извлечения CSS из `*.vue` файлов в `vue-loader` используется опция `extractCSS` (требует `vue-loader` 12.0.0+): ``` js // webpack.config.js diff --git a/ru/head.md b/ru/head.md index b4bf99ca..4beff90a 100644 --- a/ru/head.md +++ b/ru/head.md @@ -2,7 +2,7 @@ Аналогично внедрению ресурсов, управление заголовочными тегами следует той же идее: мы можем динамически присоединять данные к `context` рендерера в жизненном цикле компонента, а затем интерполировать эти данные в `template`. -> С версии >=2.3.2 вы можете напрямую получать доступ к контексту SSR в компонентах через `this.$ssrContext`. В более ранних версиях вам потребуется вручную внедрять контекст SSR, передав его в `createApp()` и выставляя его на корневом экземплере `$options` — после чего, компоненты потомки смогут получить к нему доступ через `this.$root.$options.ssrContext`. +> С версии 2.3.2+ вы можете напрямую получать доступ к контексту SSR в компонентах через `this.$ssrContext`. В более ранних версиях вам потребуется вручную внедрять контекст SSR, передав его в `createApp()` и выставляя его на корневом экземплере `$options` — после чего, компоненты потомки смогут получить к нему доступ через `this.$root.$options.ssrContext`. Мы можем написать простую примесь для управления заголовком: @@ -38,7 +38,7 @@ const clientTitleMixin = { } } -// значение VUE_ENV будет определено плагином webpack.DefinePlugin +// значение `VUE_ENV` будет определено плагином `webpack.DefinePlugin` export default process.env.VUE_ENV === 'server' ? serverTitleMixin : clientTitleMixin @@ -66,7 +66,7 @@ export default { } ``` -И внутри `template`, переданного в рендерер сборки: +И внутри шаблона, переданного в рендерер сборки: ``` html From 5ddc8083a81f79119f10c1ade7e8f6a69c7f5bee Mon Sep 17 00:00:00 2001 From: Alex Sokolov Date: Thu, 7 Sep 2017 09:42:33 +0300 Subject: [PATCH 11/11] =?UTF-8?q?caching.md=20=D0=BA=D0=B0=D0=BF=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B2?= =?UTF-8?q?=D0=BE=D0=B7=D0=B2=D1=80=D0=B0=D1=89=D0=B5=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ru/caching.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ru/caching.md b/ru/caching.md index 4824918a..6f8314fe 100644 --- a/ru/caching.md +++ b/ru/caching.md @@ -6,7 +6,7 @@ Приложение с рендерингом на стороне сервера в большинстве случаев зависит от внешних данных, поэтому содержимое является динамическим, по своей природе, и не может кэшироваться в течение длительных периодов времени. Однако, если содержимое не зависит от конкретного пользователя (например, для одного и того же URL всегда отображается одинаковое содержимое всем пользователям), мы можем использовать стратегию под названием [микро-кэширование](https://www.nginx.com/blog/benefits-of-microcaching-nginx/), чтобы значительно улучшить возможности нашего приложения для обработки большого трафика. -Это обычно реализуется на уровне nginx, но мы также можем реализовать его в Node.js: +Это обычно реализуется на уровне Nginx, но мы также можем реализовать его в Node.js: ``` js const microCache = LRU({