Appearance
Server-Side Rendering
Remarque
SSR fait spécifiquement référence aux frameworks frontaux (par exemple React, Preact, Vue et Svelte) qui prennent en charge l'exécution de la même application dans Node.js, son pré-rendu en HTML et enfin son hydratation sur le client. Si vous recherchez une intégration avec des frameworks traditionnels côté serveur, consultez plutôt le Guide de l'intégration backend.
Le guide suivant suppose également une expérience préalable de travail avec SSR dans le framework de votre choix, et se concentrera uniquement sur les détails d'intégration spécifiques à Vite.
API de bas niveau
Il s'agit d'une API de bas niveau destinée aux auteurs de bibliothèques et de frameworks. Si votre objectif est de créer une application, assurez-vous de consulter d'abord les plugins et outils SSR de plus haut niveau dans la [section Awesome Vite SSR] (https://github.com/vitejs/awesome-vite#ssr). Cela dit, de nombreuses applications sont construites avec succès directement sur l'API bas niveau native de Vite.
Aide
Si vous avez des questions, la communauté vous aide généralement sur Vite Discord #ssr channel.
Exemples de projets
Vite fournit un support intégré pour le rendu côté serveur (SSR). Le terrain de jeu Vite contient des exemples de configurations SSR pour Vue 3 et React, qui peuvent être utilisés comme références pour ce guide :
Structure de la source
Une application SSR typique aura la structure de fichier source suivante :
- index.html
- server.js # serveur d'application principal
- src/
- main.js # exporte le code de l'application (universelle) agnostique.
- entry-client.js # monte l'application sur un élément DOM
- entry-server.js # Rend l'application en utilisant l'API SSR du framework.
Le fichier index.html
devra faire référence à entry-client.js
et inclure un placeholder où le balisage rendu pReactar le serveur devra être injecté :
html
<div id="app"><!--ssr-outlet--></div>
<script type="module" src="/src/entry-client.js"></script>
Vous pouvez utiliser n'importe quel espace réservé à la place de <!--ssr-outlet-->
, tant qu'il peut être remplacé avec précision.
Logique conditionnelle
Si vous avez besoin d'exécuter une logique conditionnelle basée sur SSR vs. client, vous pouvez utiliser
js
if (import.meta.env.SSR) {
// ... logique de serveur uniquement
}
Ceci est remplacé statiquement lors de la construction, ce qui permet de secouer l'arbre des branches inutilisées.
Configuration du serveur de développement
Lorsque vous construisez une application SSR, vous souhaitez probablement avoir un contrôle total sur votre serveur principal et découpler Vite de l'environnement de production. Il est donc recommandé d'utiliser Vite en mode middleware. Voici un exemple avec express :
server.js
js
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
import express from 'express'
import { createServer as createViteServer } from 'vite'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
async function createServer() {
const app = express()
// Create Vite server in middleware mode and configure the app type as
// 'custom', disabling Vite's own HTML serving logic so parent server
// can take control
const vite = await createViteServer({
server: { middlewareMode: true },
appType: 'custom'
})
// use vite's connect instance as middleware
// if you use your own express router (express.Router()), you should use router.use
app.use(vite.middlewares)
app.use('*', async (req, res) => {
// serve index.html - we will tackle this next
})
app.listen(5173)
}
createServer()
Ici, vite
est une instance de ViteDevServer. vite.middlewares
est une instance de Connect qui peut être utilisée comme middleware dans n'importe quel framework Node.js compatible connect.
L'étape suivante consiste à implémenter le gestionnaire *
pour servir le HTML rendu par le serveur :
js
app.use('*', async (req, res, next) => {
const url = req.originalUrl
try {
// 1. Lire l'index.html
let template = fs.readFileSync(
path.resolve(__dirname, 'index.html'),
'utf-8'
)
// 2. appliquer les transformations HTML de Vite. Ceci injecte le client Vite HMR, et // applique également les transformations HTML des plugins Vite, par ex.
// applique également les transformations HTML des plugins Vite, par exemple les préambules globaux.
// de @vitejs/plugin-react
template = await vite.transformIndexHtml(url, template)
// 3. charger l'entrée du serveur. vite.ssrLoadModule transforme automatiquement
// votre code source ESM pour être utilisable dans Node.js ! Il n'y a pas de bundling
// Il n'y a pas de bundling // requis, et fournit une invalidation efficace similaire à HMR.
const { render } = await vite.ssrLoadModule('/src/entry-server.js')
// 4. Rendez le HTML de l'application. Cela suppose que la fonction exportée `render` de entry-server.js appelle l'API SSR appropriée.
// appelle les API SSR appropriées du framework,
// par exemple ReactDOMServer.renderToString()
const appHtml = await render(url)
// 5. Injectez le HTML rendu par l'application dans le modèle.
const html = template.replace(`<!--ssr-outlet-->`, appHtml)
// 6. Renvoyer le HTML rendu.
res.status(200).set({'Content-Type' : 'text/html' }).end(html)
} catch (e) {
// Si une erreur est détectée, laissez Vite corriger la trace de la pile pour qu'elle renvoie à
// votre code source actuel.
vite.ssrFixStacktrace(e)
next(e)
}
})
Le script dev
dans package.json
doit également être modifié pour utiliser le script du serveur à la place :
diff
"scripts" : {
- "dev" : "vite"
+ "dev" : "serveur de nœuds"
}
Construction pour la production
Pour expédier un projet SSR pour la production, nous devons :
- Produire un build client comme d'habitude ;
- Produire un build SSR, qui peut être chargé directement via
import()
afin de ne pas avoir à passer par lessrLoadModule
de Vite ;
Nos scripts dans package.json
ressembleront à ceci :
json
{
"scripts" : {
"dev" : "node server",
"build:client" : "vite build --outDir dist/client",
"build:server" : "vite build --outDir dist/server --ssr src/entry-server.js "
}
}
Notez le drapeau --ssr
qui indique qu'il s'agit d'un build SSR. Il doit également spécifier l'entrée SSR.
Ensuite, dans server.js
, nous devons ajouter une logique spécifique à la production en vérifiant p
NODE_ENV
:
Au lieu de lire le fichier racine
index.html
, utilisez le fichierdist/client/index.html
comme modèle, car il contient les liens corrects vers le client.Au lieu de
await vite.ssrLoadModule('/src/entry-server.js')
, utilisezimport('./dist/server/entry-server.js')
à la place (ce fichier est le résultat de la construction du SSR).Déplacer la création et toute l'utilisation du serveur de développement
vite
derrière des branches conditionnelles dev-only, puis ajouter des middlewares de service de fichiers statiques pour servir les fichiers depuisdist/client
.
Référez-vous aux démos Vue et React pour une configuration fonctionnelle.
Génération de directives de préchargement
vite build
supporte le flag --ssrManifest
qui va générer ssr-manifest.json
dans le répertoire de sortie du build :
diff
- "build:client" : "vite build --outDir dist/client",
+ "build:client" : "vite build --outDir dist/client --ssrManifest",
Le script ci-dessus va maintenant générer dist/client/ssr-manifest.json
pour la compilation du client (Oui, le manifeste SSR est généré à partir de la compilation du client parce que nous voulons faire correspondre les ID des modules aux fichiers du client). Le manifeste contient les mappings des ID de modules vers leurs chunks et fichiers d'actifs associés.
Pour exploiter le manifeste, les frameworks doivent fournir un moyen de collecter les ID de module des composants qui ont été utilisés pendant un appel de rendu du serveur.
@vitejs/plugin-vue
prend cela en charge dès le départ et enregistre automatiquement les ID des modules des composants utilisés dans le contexte Vue SSR associé :
js
// src/entry-server.js
const ctx = {}
const html = await vueServerRenderer.renderToString(app, ctx)
// ctx.modules est maintenant un ensemble d'ID de modules qui ont été utilisés pendant le rendu.
Dans la branche de production de server.js
, nous devons lire et passer le manifeste à la fonction render
exportée par src/entry-server.js
. Cela nous fournirait suffisamment d'informations pour rendre les directives de préchargement pour les fichiers utilisés par les routes asynchrones ! Voir demo source pour un exemple complet.
Pré-rendu / SSG
Si les routes et les données nécessaires à certaines routes sont connues à l'avance, nous pouvons pré-rendre ces routes en HTML statique en utilisant la même logique que la production SSR. Cela peut également être considéré comme une forme de génération de sites statiques (SSG). Voir demo pre-render script pour un exemple fonctionnel.
SSR Externals
Les dépendances sont "externalisées" du système de modules de transformation SSR de Vite par défaut lors de l'exécution de SSR. Cela accélère à la fois le développement et la construction.
Si une dépendance doit être transformée par le pipeline de Vite, par exemple, parce que des fonctionnalités de Vite sont utilisées sans être transpilées, elles peuvent être ajoutées à ssr.noExternal
.
Pour les dépendances liées, elles ne sont pas externalisées par défaut pour profiter de l'HMR de Vite. Si cela n'est pas souhaité, par exemple, pour tester les dépendances comme si elles n'étaient pas liées, vous pouvez l'ajouter à ssr.external
.
Travailler avec des alias
Si vous avez configuré des alias qui redirigent un paquet vers un autre, vous pouvez vouloir aliaser les paquets node_modules
à la place pour que cela fonctionne pour les dépendances externalisées de SSR. Yarn et pnpm prennent tous deux en charge les alias via le préfixe npm:
.
Logique de plugin spécifique à SSR
Certains frameworks comme Vue ou Svelte compilent les composants dans des formats différents en fonction du client et du SSR. Pour supporter les transformations conditionnelles, Vite passe une propriété ssr
supplémentaire dans l'objet options
des hooks de plugin suivants :
resolveId
load
transformer
Exemple:
js
export function mySSRPlugin() {
return {
name : 'my-ssr',
transform(code, id, options) {
if (options ?.ssr) {
// effectue une transformation spécifique à ssr...
}
}
}
}
L'objet options dans load
et transform
est optionnel, le rollup n'utilise pas cet objet actuellement mais peut étendre ces crochets avec des métadonnées supplémentaires dans le futur.
Note
Avant Vite 2.7, ceci était informé aux hooks de plugins avec un paramètre ssr
positionnel au lieu d'utiliser l'objet options
. Tous les principaux frameworks et plugins sont mis à jour mais vous pouvez trouver des articles périmés en utilisant l'ancienne API.
Cible SSR
La cible par défaut pour la construction SSR est un environnement node, mais vous pouvez également exécuter le serveur dans un Web Worker. La résolution d'entrée des paquets est différente pour chaque plate-forme. Vous pouvez configurer la cible pour être un Web Worker en utilisant le ssr.target
défini à 'webworker'
.
Paquet SSR
Dans certains cas, comme pour les moteurs d'exécution webworker
, vous pouvez vouloir regrouper votre compilation SSR dans un seul fichier JavaScript. Vous pouvez activer ce comportement en mettant ssr.noExternal
à true
. Cela aura deux effets :
- Traiter toutes les dépendances comme
noExternal
. - Lancer une erreur si un build-in Node.js est importé.
Vite CLI
Les commandes CLI $ vite dev
et $ vite preview
peuvent aussi être utilisées pour les applications SSR. Vous pouvez ajouter vos middlewares SSR au serveur de développement avec configureServer
et au serveur de prévisualisation avec configurePreviewServer
.
Remarque
Utilisez un post hook pour que votre middleware SSR s'exécute après les middlewares de Vite.
Format SSR
Par défaut, Vite génère le bundle SSR en ESM. Il existe un support expérimental pour configurer ssr.format
, mais ce n'est pas recommandé. Les efforts futurs autour du développement SSR seront basés sur ESM, et CommonJS reste disponible pour une compatibilité descendante. Si l'utilisation de ESM pour SSR n'est pas possible dans votre projet, vous pouvez définir legacy.buildSsrCjsExternalHeuristics : true
pour générer un bundle CJS en utilisant la même [heuristique d'externalisation de Vite v2] (https://v2.vitejs.dev/guide/ssr.html#ssr-externals).