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..409ccde4 --- /dev/null +++ b/fr/README.md @@ -0,0 +1,52 @@ +# Guide du rendu côté serveur de Vue.js + +> **Note** : ce guide nécessite les versions minimales de Vue et des librairies : +> +> * 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é Vue 2.2 avec le SSR, vous remarquerez que la structure de code recommandé est désormais [un peu différente](./structure.md) (avec l'option [unInNewContext](./api.md#runinnewcontext) ayant pour valeur `false`). Votre application existante devrait continuer de fonctionner, mais il est recommander de migrer vers ces nouvelles recommandations. + +## Qu'est-ce que le rendu côté serveur (Server-Side Rendering, SSR) ? + +Vue.js est un framework pour créer des applications clients. Par défaut, les composants Vue produisent et manipulent le DOM dans le navigateur. Toutefois, il est aussi possible de rendre ces mêmes composants en chaînes de caractères HTML sur le serveur, les envoyer directement au navigateur, et enfin "hydrater" le balisage statique en une application entièrement interactive sur le client. + +Une application Vue rendue par le serveur peut aussi être considérée comme "isomorphique" ou "universelle", dans le sens que la majorité du code de votre application fonctionnera côté serveur **et** côté client. + +## Pourquoi le rendu côté serveur ? + +Par rapport à la traditionnelle SPA (Single-Page Application, Application Page Unique), l'avantage du SSR consiste en : + +* Un meilleur SEO, vu que les robots des moteurs de recherche verront directement la page entièrement rendue, + +* Notez qu'à partir de maintenant, Google et Bing peuvent indexer les applications JavaScript synchrones. Synchrone est le mot important ici. Si votre application commence avec une image de chargement, et qu'elle récupère du contenu via Ajax, le robot ne va pas attendre que la récupération du contenu de manière asynchrone soit terminée. Ce qui veut dire que si vous avez du contenu récupéré de manière asynchrone et où le SEO est important, le SSR pourrait être nécessaire. + +* Un chargement plus rapide, notamment avec des appareils lents, ou une connexion internet lente. Le code HTML rendu par le serveur n'a pas besoin d'attendre que le JavaScript soit téléchargé et exécuté pour être affiché. L'utilisateur de votre application verra donc plus tôt une page entièrement rendue. Cela résulte généralement en une meilleure expérience utilisateur, et peut être critique pour des applications où le chargement est directement associé avec le taux de conversion. + +Il y a également quelques points négatifs à prendre en compte en utilisant le SSR : + +* Les contraintes de développement. Le code spécifique au navigateur ne peut être utilisé que dans certains connecteurs du cycle de vie ; certaines librairies devront recevoir un traitement spécial pour être capable de fonctionner sur une application rendue par le serveur. + +* Un build setup et des besoins pour le déploiement plus complexes. Au contraire d'une SPA entièrement statique qui peut être déployée sur n'importe quel serveur de fichier statique, une application rendue par le serveur a besoin d'un environnement où un serveur Node.js peut tourner. + +* Plus de charge pour le serveur. Faire entièrement le rendu d'une application avec Node.js sera bien évidemment plus coûteux pour le processeur, que de servir des fichiers statiques. Donc si vous vous attendez à beaucoup de trafic, préparez-vous à cette charge serveur et utilisez judicieusement des stratégies de mise en cache. + +Avant d'utiliser le SSR pour votre application, la première question que vous devez vous demander est si vous en avez réellement besoin. Cela dépend principalement à quel point le temps d'affichage de votre application est important ou non. Par exemple, si vous avez créé un tableau de bord interne à votre application, et où attendre quelques centaines de millisecondes en plus n'est pas vraiment un problème, il serait exagéré d'utiliser le SSR. Cependant, dans les cas où le chargement et le rendu de la page est un point critique, le SSR peut vous aider à atteindre les meilleures performances possibles pour le chargement initial de votre application. + +## SSR vs pré-rendu + +Si vous n'êtes seulement intéressé par le SSR uniquement pour améliorer le SEO et une poignée de pages (ex: `/` , `/about` , `/contact`, etc...), alors c'est probablement que vous vous intéressez au **pré-rendu**. Au lieu d'utiliser un serveur web pour compiler du HTML à la volée, le pré-rendu génère des fichiers HTML pour des routes spécifiques, au moment de la compilation. L'avantage du pré-rendu est qu'il est beaucoup plus simple à mettre en place, et qu'il vous permet de garder votre _front-end_ entièrement statique. + +Si vous utilisez Webpack, il est alors possible d'ajouter facilement le pré-rendu avec [prerender-spa-plugin](https://github.com/chrisvfritz/prerender-spa-plugin). Il a été largement testé avec les applications Vue - et en fait, le créateur est un membre de l'équipe principale de Vue. + +## A propos de ce guide + +Ce guide se concentre sur les SPA rendues par un serveur Node.js. Mélanger le SSR de Vue avec d'autres configurations _backend_ est un sujet à part entière, et ne sera pas pas couvert dans ce guide. + +Ce guide sera très approfondi, il est donc nécessaire d'être familier avec Vue.js, et d'avoir une connaissance décente de Node.js et webpack. Si vous préférez une solution plus avancée et qui offre une meilleure expérience d'utilisation _out-of-the-box_, vous devriez essayer [Nuxt.js](https://nuxtjs.org/). Nuxt.js est construit sur le même _Vue stack_, mais elle abstrait énormément la structure de base de l'application. Elle apporte cependant quelques fonctionnalités supplémentaires, comme la génération de site statique par exemple. Toutefois, il se peut que cela ne convienne pas à votre utilisation si vous avez besoin de plus de contrôle sur la structure de votre application. Quoi qu'il en soit, il serait toujours utile de lire ce guide pour mieux comprendre son fonctionnement. + +Comme vous lisez, il serait utile de se référer à la [démo HackerNews ](https://github.com/vuejs/vue-hackernews-2.0/) officielle, qui utilise la plupart des techniques couvertes dans ce guide. + +Enfin, notez que les solutions dans ce guide ne sont pas définitives - nous avons trouvées qu'elles fonctionnaient bien pour nous, mais cela ne veut pas dire qu'elles ne peuvent pas être améliorées. Ces solutions pourront être re-travaillées à l'avenir - vous êtes libre de contribuer en soumettant des _pull requests_ ! + diff --git a/fr/SUMMARY.md b/fr/SUMMARY.md new file mode 100644 index 00000000..556e559d --- /dev/null +++ b/fr/SUMMARY.md @@ -0,0 +1,27 @@ +- [Utilisation basique](basic.md) +- [Écriture d'un code universel](universal.md) +- [Structure du code source](structure.md) +- [Gestion des routes et séparation du code](routing.md) +- [Data Pre-fetching and State](data.md) +- [Client Side Hydration](hydration.md) +- [Introducing Bundle Renderer](bundle-renderer.md) +- [Build Configuration](build-config.md) +- [CSS Management](css.md) +- [Head Management](head.md) +- [Caching](caching.md) +- [Streaming](streaming.md) +- [API Reference](api.md) + - [createRenderer](api.md#createrendereroptions) + - [createBundleRenderer](api.md#createbundlerendererbundle-options) + - [Class: Renderer](api.md#class-renderer) + - [Class: BundleRenderer](api.md#class-bundlerenderer) + - [Renderer Options](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 Plugins](api.md#webpack-plugins) diff --git a/fr/api.md b/fr/api.md new file mode 100644 index 00000000..8c82f6b5 --- /dev/null +++ b/fr/api.md @@ -0,0 +1,227 @@ +# API Reference + +## `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` + + 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, we don't need to worry about the "stateful singleton" problem we mentioned earlier. 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` whenever you can. + + 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/basic.md b/fr/basic.md new file mode 100644 index 00000000..2b2b6167 --- /dev/null +++ b/fr/basic.md @@ -0,0 +1,150 @@ +# Utilisation basique + +## Installation + +``` bash +npm install vue vue-server-renderer --save +``` + +Nous utiliserons NPM durant ce guide, mais vous pouvez utiliser [Yarn](https://yarnpkg.com/en/) à la place. + +#### Notes + +- Il est recommandé d'utiliser la version 6+ de Node.js. +- Les versions de `vue-server-renderer` et `vue` doivent correspondre. +- `vue-server-renderer` utilise certains modules natifs de Node.js, et par conséquent ne peut être utilisé qu'avec Node.js. Il se peut que nous fournissons une *build* plus simple qui pourra être utilisé dans d'autres environnements d'exécution JavaScript, dans le futur. + +## Rendu d'une instance de Vue + +``` js +// Étape 1 : Créer une instance de Vue +const Vue = require('vue') +const app = new Vue({ + template: `
Bonjour le monde
+}) +``` + +## Integration avec un serveur + +L'utilisation avec un serveur Node.js, par exemple [Express](https://expressjs.com/), est plutôt simple : + +``` 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: `