From cbad2d54666ac9c7550911eab0415a1a8beb2111 Mon Sep 17 00:00:00 2001 From: Bruno Lesieur Date: Fri, 5 May 2017 12:13:05 +0200 Subject: [PATCH 01/18] Add french directory + Translation of README.md + Translation of basic.md + Partial Translation of SUMMARY.md Signed-off-by: Bruno Lesieur --- LANGS.md | 1 + fr/README.md | 50 +++++++++++++++++ fr/SUMMARY.md | 27 ++++++++++ fr/basic.md | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 225 insertions(+) create mode 100644 fr/README.md create mode 100644 fr/SUMMARY.md create mode 100644 fr/basic.md diff --git a/LANGS.md b/LANGS.md index 25b60e8a..bf3ac484 100644 --- a/LANGS.md +++ b/LANGS.md @@ -1 +1,2 @@ * [English](en/) +* [Français](fr/) diff --git a/fr/README.md b/fr/README.md new file mode 100644 index 00000000..1e5c0de8 --- /dev/null +++ b/fr/README.md @@ -0,0 +1,50 @@ +# Guide du rendu côté serveur avec Vue.js + +> **Note :** Ce guide nécessite les versions de Vue et de ses bibliothèques de support suivantes : +> - vue & vue-server-renderer >= 2.3.0 +> - vue-router >= 2.5.0 +> - vue-loader >= 12.0.0 & vue-style-loader >= 3.0.0 + +> Si vous avez déjà utilisé le rendu côté serveur (SSR pour *Server-Side Rendering*) avec Vue 2.2, vous vous apercevrez que la structure de code recommandée est maintenant [légèrement différente](./structure.md) (avec la nouvelle option [runInNewContext](./api.md#runinnewcontext) mise à `false`). Votre application devrait continuer à fonctionner, mais il est recommandé de migrer vers les nouvelles recommandations. + +## Le rendu côté serveur ou SSR, qu'est-ce que c'est ? + +Vue.js est un framework pour créer des applications côté client. Par défaut, Vue génère en sortie un DOM manipulable dans le navigateur. Il est cependant également possible de faire le rendu des mêmes composants sous forme de chaîne de caractères HTML côté serveur, de les envoyer directement au navigateur et d'« hydrater » les balises statiques fournies en une application cliente pleinement interactive. + +Une application Vue.js rendue du côté serveur peut également être considérée comme « isomorphique » ou « universelle », dans le sens où la majorité du code est exécutable côté serveur **et** coté client. + +## Pourquoi faire du SSR ? + +En comparaison des applications monopages traditionnelles (SPA pour *Single-Page Application*), l'avantage du SSR se manifeste dans : + +- de meilleures optimisations pour les moteurs de recherche (SEO pour *Search Engine Optimisations*), ainsi les moteurs d'indexation voient directement le rendu complet de la page. + + À noter qu'à présent, Google et Bing savent parfaitement indexer des applications JavaScript synchrones. Synchrone est le mot important ici. Si votre application débute avec une animation de chargement, puis va chercher le contenu via Ajax, l'indexeur n'attendra pas que cette action soit finie. Cela signifie que si vous avez du contenu asynchrone injecté sur des pages ou la SEO est importante, du SSR serait nécessaire. + +- de meilleurs temps d'accès au contenu, en particulier pour les connexions Internet lentes ou les appareils lents. Le rendu des balises côté serveur n'a pas besoin d'attendre le chargement de tous les fichiers JavaScript pour que le code soit exécuté en vue d'être affiché. Ainsi votre utilisateur verra apparaître une page complètement rendue très tôt. Cela conduit généralement à une meilleure expérience utilisateur, ce qui peut-être critique pour les applications où le temps d'accès au contenu est directement lié au taux de conversion. + +Il y a aussi des contraintes à prendre en considération quand on utilise du SSR : + +- Des contraintes de développement. Le code spécifique aux navigateurs ne peut être utilisé que dans certains points d'ancrage (hooks) ; plusieurs bibliothèques nécessites une utilisation particulière pour être capable d'être exécutées dans une application côté serveur. + +- Il y a plus d'étapes de compilation avant démarrage et de déploiement requises. Contrairement à une SPA qui peut être déployée sur un serveur de fichiers statiques, une application rendue côté serveur nécessite un environnement où un serveur Node.js peut tourner. + +- Plus de charge côté serveur. Faire le rendue d'une application complète en Node.js est évidemment une tâche demandant plus de CPU que de simplement renvoyer des fichiers statiques. Aussi si vous vous attendez à un fort trafique, préparez-vous un serveur tenant la charge et utilisez astucieusement des stratégies de mise en cache. + +Avant d'utiliser du SSR pour vos applications, la première question que vous devriez vous poser est si vous en avez réellement besoin. Cela dépendra de l'importance du temps d'accès au contenu pour votre application. Par exemple, si vous créez une interface d'administration avec un chargement initial de quelques secondes cela importe peu ; du SSR n'aurait pas de pertinence dans ce cas. Cependant, dans le cas où l'accès au contenu est une priorité absolue, du SSR peut vous aider à obtenir les meilleures performances de chargement initial. + +## Rendu côté serveur vs. pré-rendu + +Si vous envisagez d'utiliser du SSR seulement pour améliorer votre SEO sur des pages informatives à valeur ajoutée (par ex. `/`, `/about`, `/contact`, etc), alors vous devriez plutôt utiliser du pré-rendu. Plutôt que d'utiliser un serveur web pour compiler le HTML en temps réel, faites le simple pré-rendu de vos pages statiques en HTML pour des routes bien spécifiques lors d'une phase de pré-compilation. L'avantage est que faire du pré-rendu est plus simple et vous permet de garder un site avec une partie cliente statique. + +Si vous utilisez webpack, vous pouvez facilement ajouter du pré-rendu avec le plugin [prerender-spa-plugin](https://github.com/chrisvfritz/prerender-spa-plugin). Il a particulièrement bien été testé avec des applications Vue (en fait, [son créateur](https://github.com/chrisvfritz) est lui-même un membre de l'équipe principale de Vue). + +## À propos de ce guide + +Ce guide est dédié au rendu côté serveur des applications monopages utilisant Node.js en tant que serveur web. Utiliser le SSR de Vue avec une autre configuration serveur est un sujet qui ne sera pas abordé dans ce guide. + +Ce guide va réellement entrer dans le détail et présuppose que vous êtes déjà familiarisé avec Vue.js et que vous avez un niveau de connaissance correcte concernant Node.js et webpack. Si vous préférez une solution de haut niveau fournissant une expérience de développement prête à l'emploi, vous devriez probablement essayer [Nuxt.js](http://nuxtjs.org/). Il est construit par-dessus l'écosystème de Vue et vous fourni des éléments préconçus ainsi que des fonctionnalités supplémentaires pour générer des sites web statiques. Il ne vous conviendra cependant pas si vous souhaitez avoir un contrôle plus direct sur la structure de votre application. Dans tous les cas, il reste toujours intéressant de parcourir ce guide pour mieux comprendre comment chaque élément fonctionne avec le reste. + +Au fil de votre lecture, il peut être intéressant également de vous référer à la [démo HackerNews](https://github.com/vuejs/vue-hackernews-2.0/) qui utilise bon nombre des techniques expliquées dans ce guide. + +Pour finir, notez que les solutions de ce guide ne sont pas définitives. Nous avons trouvé que cela fonctionnait bien pour nous, mais cela ne veut pas dire qu'il n'y a pas d'améliorations à faire. Nous pourrons les réviser dans le futur. N'hésitez donc pas à y contribuer en soumettant des pull requests ! diff --git a/fr/SUMMARY.md b/fr/SUMMARY.md new file mode 100644 index 00000000..2b3d3117 --- /dev/null +++ b/fr/SUMMARY.md @@ -0,0 +1,27 @@ +- [Utilisation de base](basic.md) +- [Écrire du code universel (En)](https://ssr.vuejs.org/en/universal.html) +- [Structure de code (En)](https://ssr.vuejs.org/en/structure.html) +- [Routage et fragmentation (En)](https://ssr.vuejs.org/en/routing.html) +- [Pré-chargement et état (En)](https://ssr.vuejs.org/en/data.html) +- [Hydratation côté client (En)](https://ssr.vuejs.org/en/hydration.html) +- [Introduction à l'empaquetage de rendu (En)](https://ssr.vuejs.org/en/bundle-renderer.html) +- [Configuration de compilation (En)](https://ssr.vuejs.org/en/build-config.html) +- [Gestion des CSS (En)](https://ssr.vuejs.org/en/css.html) +- [Gestion des entêtes (En)](https://ssr.vuejs.org/en/head.html) +- [Mise en cache (En)](https://ssr.vuejs.org/en/caching.html) +- [Envoi par flux (En)](https://ssr.vuejs.org/en/streaming.html) +- [Réference de l'API (En)](https://ssr.vuejs.org/en/api.html) + - [createRenderer (En)](https://ssr.vuejs.org/en/api.html#createrendereroptions) + - [createBundleRenderer (En)](https://ssr.vuejs.org/en/api.html#createbundlerendererbundle-options) + - [Class: Renderer (En)](https://ssr.vuejs.org/en/api.html#class-renderer) + - [Class: BundleRenderer (En)](https://ssr.vuejs.org/en/api.html#class-bundlerenderer) + - [Renderer Options (En)](https://ssr.vuejs.org/en/api.html#renderer-options) + - [template (En)](https://ssr.vuejs.org/en/api.html#template) + - [clientManifest (En)](https://ssr.vuejs.org/en/api.html#clientmanifest) + - [inject (En)](https://ssr.vuejs.org/en/api.html#inject) + - [shouldPreload (En)](https://ssr.vuejs.org/en/api.html#shouldpreload) + - [runInNewContext (En)](https://ssr.vuejs.org/en/api.html#runinnewcontext) + - [basedir (En)](https://ssr.vuejs.org/en/api.html#basedir) + - [cache (En)](https://ssr.vuejs.org/en/api.html#cache) + - [directives (En)](https://ssr.vuejs.org/en/api.html#directives) + - [Plugins webpack (En)](https://ssr.vuejs.org/en/api.html#webpack-plugins) diff --git a/fr/basic.md b/fr/basic.md new file mode 100644 index 00000000..be89d830 --- /dev/null +++ b/fr/basic.md @@ -0,0 +1,147 @@ +# Utilisation de base + +## Installation + +``` bash +npm install vue vue-server-renderer --save +``` + +Nous allons utiliser NPM tout au long de ce guide, n'hésitez pas à utiliser [Yarn](https://yarnpkg.com/en/) à la place. + +#### Notes + +- Il est recommandé d'utiliser une version 6 et supérieur de Node.js +- `vue-server-renderer` et `vue` doivent utiliser des numéros de version identiques. +- `vue-server-renderer` utilise plusieurs modules Node.js natifs fournis uniquement par Node.js. Nous fournirons une version exécutable qui pourra tourner sur les autres moteurs JavaScript dans le futur. + +## Faire le rendu d'une instance de Vue + +``` js +// Étape 1 : créer une instance de Vue +const Vue = require('vue') +const app = new Vue({ + template: `
Hello World
` +}) + +// Étape 2 : créer un générateur de rendu +const renderer = require('vue-server-renderer').createRenderer() + +// Étape 3 : faire le rendu de l'instance en HTML +renderer.renderToString(app, (err, html) => { + if (err) throw err + console.log(html) + // =>
Hello World
+}) +``` + +## Intégration avec un serveur + +Il est plus simple d'utiliser le code précédent avec un serveur Node.js, comme par exemple [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: `
L'URL visitée est : {{ url }}
` + }) + + renderer.renderToString(app, (err, html) => { + if (err) { + res.status(500).end('Erreur interne du serveur') + return + } + res.end(` + + + Bonjour + ${html} + + `) + }) +}) + +server.listen(8080) +``` + +## Utiliser un modèle de page + +Quand vous faites le rendu d'une application Vue, le générateur de rendu fournit uniquement les balises de votre application. Dans cet exemple, nous allons ajouter de part et d'autre la structure HTML nécessaire à toutes pages. + +Le plus simple est de directement fournir un modèle de page lors de la création du générateur de rendu. La plupart du temps, nous allons mettre le modèle de page dans son propre fichier. Par ex. `index.template.html` : + +``` html + + + Bonjour + + + + +``` + +Notez que le commentaire `` représente la zone où les balises de votre application vont être injectées. + +Nous allons ensuite lire et passer le contenu du fichier au générateur de rendu de Vue : + +``` js +const renderer = createRenderer({ + template: require('fs').readFileSync('./index.template.html', 'utf-8') +}) + +renderer.renderToString(app, (err, html) => { + console.log(html) // sera la page complète avec le contenu de l'application injecté. +}) +``` + +### Interpolation dans le modèle de page + +Le modèle de page supporte également une interpolation simple. Avec le modèle de page suivant : + +``` html + + + {\{ title }} + {\{\{ meta }}} + + + + + +``` + +Nous pouvons fournir les données d'interpolation suivantes à travers un « objet de contexte de rendu » en tant que second argument de `renderToString` : + +``` js +const context = { + title: 'Bonjour', + meta: ` + + + ` +} + +renderer.renderToString(app, context, (err, html) => { + // le titre de la page sera « Bonjour » + // avec les balises injectées +}) +``` + +L'objet `context` peut également être partagé avec l'instance de l'application de Vue, permettant aux composants de dynamiquement fournir des données pour l'interpolation du modèle de page. + +De plus, le modèle de page supporte des fonctionnalités avancées comme : + +- l'injection automatique de CSS critique lors de l'utilisation de composants `*.vue`, +- l'injection automatique de balises `` avec l'utilisation de `clientManifest`, +- l'injection automatique de l'état de Vuex pour l'hydratation cliente avec prévention XSS. + +Nous discuterons de cela quand nous introduirons ces concepts plus tard dans le guide. From 7eb474186e5f9abc24984ad657aa99f2906c9b68 Mon Sep 17 00:00:00 2001 From: Bruno Lesieur Date: Fri, 5 May 2017 12:14:21 +0200 Subject: [PATCH 02/18] Change all `Webpack` occurences to `webpack` + Change `hello` to `Hello` from basic.md (same for `world`/`World`) Signed-off-by: Bruno Lesieur --- en/README.md | 2 +- en/SUMMARY.md | 2 +- en/api.md | 2 +- en/basic.md | 4 ++-- en/structure.md | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/en/README.md b/en/README.md index 084c25b9..f1eacdfa 100644 --- a/en/README.md +++ b/en/README.md @@ -37,7 +37,7 @@ Before using SSR for your app, the first question you should ask it whether you If you're only investigating SSR to improve the SEO of a handful of marketing pages (e.g. `/`, `/about`, `/contact`, etc), then you probably want __prerendering__ instead. Rather than using a web server to compile HTML on-the-fly, prerendering simply generates static HTML files for specific routes at build time. The advantage is setting up prerendering is much simpler and allows you to keep your frontend as a fully static site. -If you're using Webpack, you can easily add prerendering with the [prerender-spa-plugin](https://github.com/chrisvfritz/prerender-spa-plugin). It's been extensively tested with Vue apps - and in fact, [the creator](https://github.com/chrisvfritz) is a member of the Vue core team. +If you're using webpack, you can easily add prerendering with the [prerender-spa-plugin](https://github.com/chrisvfritz/prerender-spa-plugin). It's been extensively tested with Vue apps - and in fact, [the creator](https://github.com/chrisvfritz) is a member of the Vue core team. ## About This Guide diff --git a/en/SUMMARY.md b/en/SUMMARY.md index efd9eaf7..2d819948 100644 --- a/en/SUMMARY.md +++ b/en/SUMMARY.md @@ -24,4 +24,4 @@ - [basedir](api.md#basedir) - [cache](api.md#cache) - [directives](api.md#directives) - - [Webpack Plugins](api.md#webpack-plugins) + - [webpack Plugins](api.md#webpack-plugins) diff --git a/en/api.md b/en/api.md index f82bfd3a..26dc58f1 100644 --- a/en/api.md +++ b/en/api.md @@ -212,7 +212,7 @@ See [Introducing the Server Bundle](./bundle-renderer.md) and [Build Configurati As an example, check out [`v-show`'s server-side implementation](https://github.com/vuejs/vue/blob/dev/src/platforms/web/server/directives/show.js). -## Webpack Plugins +## webpack Plugins The webpack plugins are provided as standalone files and should be required directly: diff --git a/en/basic.md b/en/basic.md index bc50f593..7d15b644 100644 --- a/en/basic.md +++ b/en/basic.md @@ -30,7 +30,7 @@ const renderer = require('vue-server-renderer').createRenderer() renderer.renderToString(app, (err, html) => { if (err) throw err console.log(html) - // =>
hello world
+ // =>
Hello World
}) ``` @@ -131,7 +131,7 @@ const context = { } renderer.renderToString(app, context, (err, html) => { - // page title will be "hello" + // page title will be "Hello" // with meta tags injected }) ``` diff --git a/en/structure.md b/en/structure.md index 930240fb..05369e50 100644 --- a/en/structure.md +++ b/en/structure.md @@ -57,7 +57,7 @@ So the basic idea is we will be using webpack to bundle our app for both client We will discuss the details of the setup in later sections - for now, let's just assume we've got the build setup figured out and we can write our Vue app code with webpack enabled. -## Code Structure with Webpack +## Code Structure with webpack Now that we are using webpack to process the app for both server and client, the majority of our source code can be written in a universal fashion, with access to all the webpack-powered features. At the same time, there are [a number of things](./universal.md) you should keep in mind when writing universal code. From 5162352a9b381195b76493967cb74bbd8fe73c96 Mon Sep 17 00:00:00 2001 From: Bruno Lesieur Date: Fri, 5 May 2017 12:18:05 +0200 Subject: [PATCH 03/18] =?UTF-8?q?Remove=20extra=20`\`=20to=20avoid=20Gitbo?= =?UTF-8?q?ok=20to=20=C2=AB=20parse=20=C2=BB=20`{{`=20and=20`{{{`=20leadin?= =?UTF-8?q?g=20to=20an=20error.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bruno Lesieur --- fr/basic.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fr/basic.md b/fr/basic.md index be89d830..65a36576 100644 --- a/fr/basic.md +++ b/fr/basic.md @@ -110,8 +110,8 @@ Le modèle de page supporte également une interpolation simple. Avec le modèle ``` html - {\{ title }} - {\{\{ meta }}} + {{ title }} + {{{ meta }}} From 35465e727029f453cf4fd5afe189ffa0441a8abe Mon Sep 17 00:00:00 2001 From: Bruno Lesieur Date: Fri, 5 May 2017 12:44:32 +0200 Subject: [PATCH 04/18] Add all still in translation page with this mention to invite reader to participate. + reintroduction of FR link into `SUMMARY.md` --- fr/SUMMARY.md | 52 ++++----- fr/api.md | 237 ++++++++++++++++++++++++++++++++++++++ fr/build-config.md | 216 +++++++++++++++++++++++++++++++++++ fr/bundle-renderer.md | 52 +++++++++ fr/caching.md | 87 ++++++++++++++ fr/css.md | 114 +++++++++++++++++++ fr/data.md | 259 ++++++++++++++++++++++++++++++++++++++++++ fr/head.md | 90 +++++++++++++++ fr/hydration.md | 32 ++++++ fr/routing.md | 153 +++++++++++++++++++++++++ fr/streaming.md | 33 ++++++ fr/structure.md | 123 ++++++++++++++++++++ fr/universal.md | 31 +++++ 13 files changed, 1453 insertions(+), 26 deletions(-) create mode 100644 fr/api.md create mode 100644 fr/build-config.md create mode 100644 fr/bundle-renderer.md create mode 100644 fr/caching.md create mode 100644 fr/css.md create mode 100644 fr/data.md create mode 100644 fr/head.md create mode 100644 fr/hydration.md create mode 100644 fr/routing.md create mode 100644 fr/streaming.md create mode 100644 fr/structure.md create mode 100644 fr/universal.md diff --git a/fr/SUMMARY.md b/fr/SUMMARY.md index 2b3d3117..95bc4ece 100644 --- a/fr/SUMMARY.md +++ b/fr/SUMMARY.md @@ -1,27 +1,27 @@ - [Utilisation de base](basic.md) -- [Écrire du code universel (En)](https://ssr.vuejs.org/en/universal.html) -- [Structure de code (En)](https://ssr.vuejs.org/en/structure.html) -- [Routage et fragmentation (En)](https://ssr.vuejs.org/en/routing.html) -- [Pré-chargement et état (En)](https://ssr.vuejs.org/en/data.html) -- [Hydratation côté client (En)](https://ssr.vuejs.org/en/hydration.html) -- [Introduction à l'empaquetage de rendu (En)](https://ssr.vuejs.org/en/bundle-renderer.html) -- [Configuration de compilation (En)](https://ssr.vuejs.org/en/build-config.html) -- [Gestion des CSS (En)](https://ssr.vuejs.org/en/css.html) -- [Gestion des entêtes (En)](https://ssr.vuejs.org/en/head.html) -- [Mise en cache (En)](https://ssr.vuejs.org/en/caching.html) -- [Envoi par flux (En)](https://ssr.vuejs.org/en/streaming.html) -- [Réference de l'API (En)](https://ssr.vuejs.org/en/api.html) - - [createRenderer (En)](https://ssr.vuejs.org/en/api.html#createrendereroptions) - - [createBundleRenderer (En)](https://ssr.vuejs.org/en/api.html#createbundlerendererbundle-options) - - [Class: Renderer (En)](https://ssr.vuejs.org/en/api.html#class-renderer) - - [Class: BundleRenderer (En)](https://ssr.vuejs.org/en/api.html#class-bundlerenderer) - - [Renderer Options (En)](https://ssr.vuejs.org/en/api.html#renderer-options) - - [template (En)](https://ssr.vuejs.org/en/api.html#template) - - [clientManifest (En)](https://ssr.vuejs.org/en/api.html#clientmanifest) - - [inject (En)](https://ssr.vuejs.org/en/api.html#inject) - - [shouldPreload (En)](https://ssr.vuejs.org/en/api.html#shouldpreload) - - [runInNewContext (En)](https://ssr.vuejs.org/en/api.html#runinnewcontext) - - [basedir (En)](https://ssr.vuejs.org/en/api.html#basedir) - - [cache (En)](https://ssr.vuejs.org/en/api.html#cache) - - [directives (En)](https://ssr.vuejs.org/en/api.html#directives) - - [Plugins webpack (En)](https://ssr.vuejs.org/en/api.html#webpack-plugins) +- [Écrire du code universel (En)](universal.md) +- [Structure de code (En)](structure.md) +- [Routage et fragmentation (En)](routing.md) +- [Pré-chargement et état (En)](data.md) +- [Hydratation côté client (En)](hydration.md) +- [Introduction à l'empaquetage (En)](bundle-renderer.md) +- [Configuration de pré-compilation (En)](build-config.md) +- [Gestion des CSS (En)](css.md) +- [Gestion des entêtes (En)](head.md) +- [Mise en cache (En)](caching.md) +- [Envoi par flux (En)](streaming.md) +- [Réference de l'API (En)](api.md) + - [createRenderer (En)](api.md#createrendereroptions) + - [createBundleRenderer (En)](api.md#createbundlerendererbundle-options) + - [Class: Renderer (En)](api.md#class-renderer) + - [Class: BundleRenderer (En)](api.md#class-bundlerenderer) + - [Renderer Options (En)](api.md#renderer-options) + - [template (En)](api.md#template) + - [clientManifest (En)](api.md#clientmanifest) + - [inject (En)](api.md#inject) + - [shouldPreload (En)](api.md#shouldpreload) + - [runInNewContext (En)](api.md#runinnewcontext) + - [basedir (En)](api.md#basedir) + - [cache (En)](api.md#cache) + - [directives (En)](api.md#directives) + - [Plugins webpack (En)](api.md#webpack-plugins) diff --git a/fr/api.md b/fr/api.md new file mode 100644 index 00000000..bcf9a099 --- /dev/null +++ b/fr/api.md @@ -0,0 +1,237 @@ +# Réference de l'API (En)

*Cette page est en cours de traduction française. Revenez une autre fois pour lire une traduction achevée ou [participez à la traduction française ici](https://github.com/vuejs-fr/vue-ssr-docs).* + +## `createRenderer([options])` + +Create a [`Renderer`](#class-renderer) instance with (optional) [options](#renderer-options). + +``` js +const { createRenderer } = require('vue-server-renderer') +const renderer = createRenderer({ ... }) +``` + +## `createBundleRenderer(bundle[, options])` + +Create a [`BundleRenderer`](#class-bundlerenderer) instance with a server bundle and (optional) [options](#renderer-options). + +``` js +const { createBundleRenderer } = require('vue-server-renderer') +const renderer = createBundleRenderer(serverBundle, { ... }) +``` + +The `serverBundle` argument can be one of the following: + +- An absolute path to generated bundle file (`.js` or `.json`). Must start with `/` to be treated as a file path. + +- A bundle object generated by webpack + `vue-server-renderer/server-plugin`. + +- A string of JavaScript code (not recommended). + +See [Introducing the Server Bundle](./bundle-renderer.md) and [Build Configuration](./build-config.md) for more details. + +## `Class: Renderer` + +- #### `renderer.renderToString(vm[, context], callback)` + + Render a Vue instance to string. The context object is optional. The callback is a typical Node.js style callback where the first argument is the error and the second argument is the rendered string. + +- #### `renderer.renderToStream(vm[, context])` + + Render a Vue instance to a Node.js stream. The context object is optional. See [Streaming](./streaming.md) for more details. + +## `Class: BundleRenderer` + +- #### `bundleRenderer.renderToString([context, ]callback)` + + Render the bundle to a string. The context object is optional. The callback is a typical Node.js style callback where the first argument is the error and the second argument is the rendered string. + +- #### `bundleRenderer.renderToStream([context])` + + Render the bundle to a Node.js stream. The context object is optional. See [Streaming](./streaming.md) for more details. + +## Renderer Options + +- #### `template` + + Provide a template for the entire page's HTML. The template should contain a comment `` which serves as the placeholder for rendered app content. + + The template also supports basic interpolation using the render context: + + - Use double-mustache for HTML-escaped interpolation; + - Use triple-mustache for non-HTML-escaped interpolation. + + The template automatically injects appropriate content when certain data is found on the render context: + + - `context.head`: (string) any head markup that should be injected into the head of the page. + + - `context.styles`: (string) any inline CSS that should be injected into the head of the page. Note this property will be automatically populated if using `vue-loader` + `vue-style-loader` for component CSS. + + - `context.state`: (Object) initial Vuex store state that should be inlined in the page as `window.__INITIAL_STATE__`. The inlined JSON is automatically sanitized with [serialize-javascript](https://github.com/yahoo/serialize-javascript) to prevent XSS. + + In addition, when `clientManifest` is also provided, the template automatically injects the following: + + - Client-side JavaScript and CSS assets needed by the render (with async chunks automatically inferred); + - Optimal `` resource hints for the rendered page. + + You can disable all automatic injections by also passing `inject: false` to the renderer. + + See also: + + - [Using a Page Template](./basic.md#using-a-page-template) + - [Manual Asset Injection](./build-config.md#manual-asset-injection) + +- #### `clientManifest` + + - 2.3.0+ + - only used in `createBundleRenderer` + + Provide a client build manifest object generated by `vue-server-renderer/server-plugin`. The client manifest provides the bundle renderer with the proper information for automatic asset injection into the HTML template. For more details, see [Generating clientManifest](./build-config.md#generating-clientmanifest). + +- #### `inject` + + - 2.3.0+ + + Controls whether to perform automatic injections when using `template`. Defaults to `true`. + + See also: [Manual Asset Injection](./build-config.md#manual-asset-injection). + +- #### `shouldPreload` + + - 2.3.0+ + + A function to control what files should have `` resource hints generated. + + By default, only JavaScript and CSS files will be preloaded, as they are absolutely needed for your application to boot. + + For other types of assets such as images or fonts, preloading too much may waste bandwidth and even hurt performance, so what to preload will be scenario-dependent. You can control precisely what to preload using the `shouldPreload` option: + + ``` js + const renderer = createBundleRenderer(bundle, { + template, + clientManifest, + shouldPreload: (file, type) => { + // type is inferred based on the file extension. + // https://fetch.spec.whatwg.org/#concept-request-destination + if (type === 'script' || type === 'style') { + return true + } + if (type === 'font') { + // only preload woff2 fonts + return /\.woff2$/.test(file) + } + if (type === 'image') { + // only preload important images + return file === 'hero.jpg' + } + } + }) + ``` + +- #### `runInNewContext` + + - 2.3.0+ + - only used in `createBundleRenderer` + - Expects: `boolean | 'once'` (`'once'` only supported in 2.3.1+) + + By default, for each render the bundle renderer will create a fresh V8 context and re-execute the entire bundle. This has some benefits - for example, the app code is isolated from the server process and we don't need to worry about the [stateful singleton problem](./structure.md#avoid-stateful-singletons) mentioned in the docs. However, this mode comes at some considerable performance cost because re-executing the bundle is expensive especially when the app gets bigger. + + This option defaults to `true` for backwards compatibility, but it is recommended to use `runInNewContext: false` or `runInNewContext: 'once'` whenever you can. + + > In 2.3.0 this option has a bug where `runInNewContext: false` still executes the bundle using a separate global context. The following information assumes version 2.3.1+. + + With `runInNewContext: false`, the bundle code will run in the same `global` context with the server process, so be careful about code that modifies `global` in your application code. + + With `runInNewContext: 'once'` (2.3.1+), the bundle is evaluated in a separate `global` context, however only once at startup. This provides better app code isolation since it prevents the bundle from accidentally polluting the server process' `global` object. The caveats are that: + + 1. Dependencies that modifies `global` (e.g. polyfills) cannot be externalized in this mode; + 2. Values returned from the bundle execution will be using different global constructors, e.g. an error caught inside the bundle will not be an instance of `Error` in the server process. + + See also: [Source Code Structure](./structure.md) + +- #### `basedir` + + - 2.2.0+ + - only used in `createBundleRenderer` + + Explicitly declare the base directory for the server bundle to resolve `node_modules` dependencies from. This is only needed if your generated bundle file is placed in a different location from where the externalized NPM dependencies are installed, or your `vue-server-renderer` is npm-linked into your current project. + +- #### `cache` + + Provide a [component cache](./caching.md#component-level-caching) implementation. The cache object must implement the following interface (using Flow notations): + + ``` js + type RenderCache = { + get: (key: string, cb?: Function) => string | void; + set: (key: string, val: string) => void; + has?: (key: string, cb?: Function) => boolean | void; + }; + ``` + + A typical usage is passing in an [lru-cache](https://github.com/isaacs/node-lru-cache): + + ``` js + const LRU = require('lru-cache') + + const renderer = createRenderer({ + cache: LRU({ + max: 10000 + }) + }) + ``` + + Note that the cache object should at least implement `get` and `set`. In addition, `get` and `has` can be optionally async if they accept a second argument as callback. This allows the cache to make use of async APIs, e.g. a redis client: + + ``` js + 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) + } + } + }) + ``` + +- #### `directives` + + Allows you to provide server-side implementations for your custom directives: + + ``` js + const renderer = createRenderer({ + directives: { + example (vnode, directiveMeta) { + // transform vnode based on directive binding metadata + } + } + }) + ``` + + As an example, check out [`v-show`'s server-side implementation](https://github.com/vuejs/vue/blob/dev/src/platforms/web/server/directives/show.js). + +## webpack Plugins + +The webpack plugins are provided as standalone files and should be required directly: + +``` js +const VueSSRServerPlugin = require('vue-server-renderer/server-plugin') +const VueSSRClientPlugin = require('vue-server-renderer/client-plugin') +``` + +The default files generated are: + +- `vue-ssr-server-bundle.json` for the server plugin; +- `vue-ssr-client-manifest.json` for the client plugin. + +The filenames can be customized when creating the plugin instances: + +``` js +const plugin = new VueSSRServerPlugin({ + filename: 'my-server-bundle.json' +}) +``` + +See [Build Configuration](./build-config.md) for more information. diff --git a/fr/build-config.md b/fr/build-config.md new file mode 100644 index 00000000..6b5eef97 --- /dev/null +++ b/fr/build-config.md @@ -0,0 +1,216 @@ +# Configuration de pré-compilation (En)

*Cette page est en cours de traduction française. Revenez une autre fois pour lire une traduction achevée ou [participez à la traduction française ici](https://github.com/vuejs-fr/vue-ssr-docs).* + +We will assume you already know how to configure webpack for a client-only project. The config for an SSR project will be largely similar, but we suggest breaking the config into three files: *base*, *client* and *server*. The base config contains config shared for both environments, such as output path, aliases, and loaders. The server config and client config can simply extend the base config using [webpack-merge](https://github.com/survivejs/webpack-merge). + +## Server Config + +The server config is meant for generating the server bundle that will be passed to `createBundleRenderer`. It should look like this: + +``` 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, { + // Point entry to your app's server entry file + entry: '/path/to/entry-server.js', + + // This allows webpack to handle dynamic imports in a Node-appropriate + // fashion, and also tells `vue-loader` to emit server-oriented code when + // compiling Vue components. + target: 'node', + + // For bundle renderer source map support + devtool: 'source-map', + + // This tells the server bundle to use Node-style exports + output: { + libraryTarget: 'commonjs2' + }, + + // https://webpack.js.org/configuration/externals/#function + // https://github.com/liady/webpack-node-externals + // Externalize app dependencies. This makes the server build much faster + // and generates a smaller bundle file. + externals: nodeExternals({ + // do not externalize dependencies that need to be processed by webpack. + // you can add more file types here e.g. raw *.vue files + // you should also whitelist deps that modifies `global` (e.g. polyfills) + whitelist: /\.css$/ + }), + + // This is the plugin that turns the entire output of the server build + // into a single JSON file. The default file name will be + // `vue-ssr-server-bundle.json` + plugins: [ + new VueSSRServerPlugin() + ] +}) +``` + +After `vue-ssr-server-bundle.json` has been generated, simply pass the file path to `createBundleRenderer`: + +``` js +const { createBundleRenderer } = require('vue-server-renderer') +const renderer = createBundleRenderer('/path/to/vue-ssr-server-bundle.json', { + // ...other renderer options +}) +``` + +Alternatively, you can also pass the bundle as an Object to `createBundleRenderer`. This is useful for hot-reload during development - see the HackerNews demo for a [reference setup](https://github.com/vuejs/vue-hackernews-2.0/blob/master/build/setup-dev-server.js). + +### Externals Caveats + +Notice that in the `externals` option we are whitelisting CSS files. This is because CSS imported from dependencies should still be handled by webpack. If you are importing any other types of files that also rely on webpack (e.g. `*.vue`, `*.sass`), you should add them to the whitelist as well. + +If you are using `runInNewContext: 'once'` or `runInNewContext: true`, then you also need to whitelist polyfills that modify `global`, e.g. `babel-polyfill`. This is because when using the new context mode, **code inside a server bundle has its own `global` object.** Since you don't really need it on the server when using Node 7.6+, it's actually easier to just import it in the client entry. + +## Client Config + +The client config can remain largely the same with the base config. Obviously you need to point `entry` to your client entry file. Aside from that, if you are using `CommonsChunkPlugin`, make sure to use it only in the client config because the server bundle requires a single entry chunk. + +### Generating `clientManifest` + +> requires version 2.3.0+ + +In addition to the server bundle, we can also generate a client build manifest. With the client manifest and the server bundle, the renderer now has information of both the server *and* client builds, so it can automatically infer and inject [preload / prefetch directives](https://css-tricks.com/prefetching-preloading-prebrowsing/) and css links / script tags into the rendered HTML. + +The benefits is two-fold: + +1. It can replace `html-webpack-plugin` for injecting the correct asset URLs when there are hashes in your generated filenames. + +2. When rendering a bundle that leverages webpack's on-demand code splitting features, we can ensure the optimal chunks are preloaded / prefetched, and also intelligently inject ` + + + + +` +``` + +### Manual Asset Injection + +By default, asset injection is automatic when you provide the `template` render option. But sometimes you might want finer-grained control over how assets are injected into the template, or maybe you are not using a template at all. In such a case, you can pass `inject: false` when creating the renderer and manually perform asset injection. + +In the `renderToString` callback, the `context` object you passed in will expose the following methods: + +- `context.renderStyles()` + + This will return inline `