SSR et SSG
EmberKit propose quatre modes de rendu contrôlés par emberkit.config.ts. Le plugin Vite gère le SSR en développement ; le CLI build les bundles client et serveur et peut pré-rendre les routes statiques au build time.
Modes de rendu
| Mode | Sortie du build | Runtime | Idéal pour |
|---|---|---|---|
hybrid default | Bundle client + serveur + ssr-manifest.json ; routes statiques pré-rendues en fichiers HTML | HTML pré-rendu pour chemins statiques ; SSR pour routes dynamiques ([param]) | La plupart des apps (docs, marketing + pages dynamiques) |
static | Comme hybrid, mais toutes les routes non dynamiques pré-rendues au build time | Fichiers statiques uniquement (pas de serveur requis) | Blogs, sites marketing, documentation |
ssr | Bundle client + serveur + manifest ; pas d'étape de pré-render | Chaque requête HTML rendue côté serveur | Contenu personnalisé ou changeant souvent |
spa | Bundle client uniquement | Routage côté client ; le dev server ignore le middleware SSR | Dashboards, panneaux admin, apps entièrement client |
Classification des routes
Pendant emberkit build, chaque fichier sous src/routes/ devient une entrée du manifest :
- Route statique — le chemin n'a pas de segments dynamiques (p. ex.
/,/about,/docs/installation) - Route dynamique — le chemin contient un paramètre de segment (p. ex.
/blog/:slugdepuis[slug].tsx)
En mode hybrid, les routes statiques sont écrites dans dist/.../index.html au build time. Les routes dynamiques sont rendues à la requête via dist/server/entry-server.js.
Configuration
Créez emberkit.config.ts à la racine du projet (ou exécutez emberkit generate config) :
import { defineConfig } from '@emberkit/core';
export default defineConfig({
mode: 'hybrid', // 'static' | 'ssr' | 'spa' | 'hybrid'
server: {
port: 3000,
host: 'localhost',
},
build: {
outDir: 'dist',
target: 'esnext',
},
// Optionnel : fusionner des options Vite supplémentaires
vite: {
plugins: [/* emberkitVitePlugin(), tailwindcss(), … */],
},
});
Enregistrez le plugin Vite dans vite.config.ts (inclus dans les templates CLI) :
import { defineConfig } from 'vite';
import { emberkitVitePlugin } from '@emberkit/core/vite-plugin';
export default defineConfig({
plugins: [emberkitVitePlugin()],
esbuild: {
jsxImportSource: '@emberkit/core',
},
});
Le plugin lit emberkit.config.ts pour mode, routeDir, options markdown et compression. Sans fichier de config, hybrid est la valeur par défaut.
Développement
pnpm dev # emberkit dev — Vite + HMR
Pour tous les modes sauf spa, le dev server exécute le middleware SSR sur les navigations HTML :
- Ignore assets, HMR et requêtes non HTML
- Charge l'entrée SSR virtuelle et appelle
render(url, server) - Injecte le markup rendu dans
index.htmlà#app(ou<body id="app">)
Consultez le code source de la page dans le navigateur pour confirmer le HTML rendu côté serveur avant l'hydratation.
Build de production
pnpm build # emberkit build
| Mode | Étapes |
|---|---|
spa | Bundle client → dist/ |
ssr | Bundle client → bundle SSR → ssr-manifest.json |
hybrid | Client → SSR → manifest → pré-render des routes statiques |
static | Client → SSR → manifest → pré-render de toutes les routes non dynamiques |
Artefacts du build :
dist/
├── index.html # Shell client (et / pour l'accueil pré-rendu)
├── assets/ # JS, CSS, chunks hashés
├── ssr-manifest.json # mode, routes[], flags isStatic
├── server/
│ └── entry-server.js # Renderer SSR (sauf si vous fournissez src/entry-server.tsx)
└── about/
└── index.html # Route statique pré-rendue (hybrid/static)
Preview et serveurs de production
pnpm preview # emberkit preview — vérification locale rapide (port 4173 par défaut)
pnpm serve # emberkit serve — serveur de production via ssr-manifest.json
Preview sert les fichiers statiques et appelle entry-server.js pour les modes SSR.
Serve résout les requêtes dans l'ordre : asset statique → path/index.html pré-rendu → SSR (mode ssr, ou routes dynamiques en hybrid) → fallback SPA vers index.html racine.
Entrée serveur personnalisée
Ajoutez src/entry-server.ts ou src/entry-server.tsx pour remplacer le shim SSR généré. Exportez render(url) retournant { html, status } ou une chaîne HTML.
Métadonnées de route (head SSR intégré)
L'entrée serveur par défaut injecte les exports optionnels de route dans <head> :
// src/routes/about.tsx
export const metadata = {
title: 'About — My App',
description: 'Learn more about us',
};
export default function AboutPage() {
return <main><h1>About</h1></main>;
}
Pour des balises head déclaratives depuis les composants, utilisez le composant <Head> — il met à jour le DOM côté client et enregistre les balises pendant le rendu. Voir Head pour les détails.
Pages d'erreur personnalisées
Placez-les dans src/routes/ (pas imbriquées sous un segment) :
| Fichier | Quand utilisé |
|---|---|
404.tsx | Aucune route ne correspond |
500.tsx | Erreur non capturée lors du rendu d'une route |
Sans ces fichiers, EmberKit affiche des pages d'erreur intégrées (identiques à la navigation client). Les pages personnalisées reçoivent pathname pour le 404 et error pour le 500.
// src/routes/404.tsx
export default function NotFound() {
return (
<main>
<h1>404</h1>
<p>Page not found</p>
</main>
);
}
Props de routes dynamiques
Le SSR passe params au composant de route correspondant :
// src/routes/blog/[slug].tsx
import type { RouteParams } from '@emberkit/core';
export default function Post({ params }: RouteParams<{ slug: string }>) {
return <article><h1>{params.slug}</h1></article>;
}
Côté client, le runtime fournit aussi params, query et request via RouteParams. Voir Routing.
APIs HTML bas niveau
Ces utilitaires vivent dans @emberkit/core pour serveurs personnalisés et tests :
renderToHTMLString
import { renderToHTMLString } from '@emberkit/core';
const fragment = renderToHTMLString(<Page />);
// Fragment HTML (contenu body uniquement)
renderToHTMLString échappe le texte et les attributs string pour une sortie SSR sûre.
Registre head
import { drainHeadContent } from '@emberkit/core';
// Après rendu de composants utilisant <Head> :
const headTags = drainHeadContent();
Utilisez ceci dans un entry-server personnalisé quand vous avez besoin du support complet de <Head> en SSR.
Helpers internes
renderSSR, createHtmlDocument et createStreamingRenderer existent dans le package core pour des intégrations avancées mais ne font pas partie de la surface d'export publique de @emberkit/core aujourd'hui. Préférez le pipeline CLI ou renderToHTMLString + drainHeadContent pour les serveurs personnalisés.
Hydratation après SSR
Le HTML serveur inclut les indices data-ek-bind et les ids handler data-ekclick pour les régions interactives. L'entrée client reconnecte signals et événements sans re-rendre l'arbre complet. Détails : Hydratation.
Performance (pourquoi la vitesse est l'objectif)
Les modes de rendu EmberKit existent pour minimiser le temps jusqu'au contenu et le travail client :
| Technique | Bénéfice vitesse |
|---|---|
| SSR / pré-render | Les utilisateurs voient le HTML immédiatement ; pas de shell vide en attente de JS |
Pré-render static / hybrid | Chemins statiques servis depuis disque ou CDN — TTFB très bas |
| Hydratation sélective | Moins de parse/exécution JS ; Time to Interactive plus rapide sur pages riches |
| Liaison DOM par signals | Les mises à jour évitent le diffing virtual DOM — seuls les nœuds liés changent |
La vitesse est le premier principe du framework ; le poids et le zéro JS par défaut le soutiennent. Voir Introduction.
Déploiement edge
Déployez dist/ pré-rendu sur n'importe quel hôte statique, ou exécutez entry-server.js sur Node, Bun ou adaptateurs edge. Voir Déploiement edge.
Prochaines étapes
- Hydratation — Interactivité client sélective
- Routing — Routes basées sur fichiers, layouts, loaders
- Head — Gestion déclarative de
<head> - Déploiement edge — Cloudflare Workers et Deno