---
title: "Génération statique"
headingIds:
  [
    "static-generation",
    "when-to-use-static-generation",
    "pure-static",
    "with-deferred-fragments",
    "on-demand-regeneration",
  ]
---

# Génération statique

Générez des fichiers HTML avec les mêmes composants que votre serveur.

## Quand utiliser la génération statique

Le statique convient aux pages stables, aux builds de documentation et aux déploiements sans serveur de rendu permanent.

## Statique pur

Pour une page entièrement statique, rendez le document et écrivez la chaîne HTML dans un fichier. Aucun traitement client n’est nécessaire.

```tsx
import type { JSX } from "@vincle/core";

import { renderToStatic } from "@vincle/flow";
import { writeFile } from "node:fs/promises";

declare const pages: { Component: () => JSX.Element; out: string }[];

await renderToStatic(async (ctx) => {
  await Promise.all(
    pages.map(async (page) => {
      const html = await ctx.renderPage(() => <page.Component />);
      await writeFile(page.out, "<!DOCTYPE html>\n" + html);
    }),
  );
});
```

## Avec des fragments différés

Configurez `adapter` et `generatePath` pour les régions différées. Écrivez la page initiale puis les fragments avec `emitFragments`, aux URL utilisées par les emplacements.

```tsx
import type { JSX } from "@vincle/core";

import { renderToStatic } from "@vincle/flow";
import { NativeAdapter } from "@vincle/flow/adapters";
import { writeFile } from "node:fs/promises";

declare const pages: { Component: () => JSX.Element; out: string }[];

await renderToStatic(
  async (ctx) => {
    for (const page of pages) {
      const html = await ctx.renderPage(() => <page.Component />);
      await writeFile(page.out, "<!DOCTYPE html>\n" + html);
    }

    // One .html file per deferred fragment.
    await ctx.emitFragments((_id, url, html) => writeFile("./dist" + url, html));
  },
  { adapter: NativeAdapter },
);
```

## Régénération à la demande

Une route peut régénérer un fragment avec `renderFragment`. Conservez le même adaptateur et le même calcul de chemin que lors du build initial.

```tsx
import { renderFragment } from "@vincle/flow";
import { NativeAdapter } from "@vincle/flow/adapters";

declare function fetchPrice(symbol: string): Promise<{ value: number }>;

// A Netlify/Vercel Edge Function: both run standard Request → Response
// handlers, so this needs no platform SDK import.
export default async function handler(req: Request): Promise<Response> {
  const symbol = new URL(req.url).searchParams.get("symbol");
  if (!symbol) return new Response("Missing symbol", { status: 400 });

  const price = await fetchPrice(symbol);
  const { url, html } = await renderFragment(
    `price-${symbol}`,
    <span>{price.value.toFixed(2)}</span>,
    { adapter: NativeAdapter },
  );

  // `url` matches the path the full build already wrote this fragment to,
  // upload `html` there (blob store, on-demand revalidation, CDN purge +
  // PUT…). The shell page that includes it never needs rebuilding.
  return Response.json({ url, html });
}
```
