Désormais avec création de pages par IA via le serveur MCP

Routes et pages

Trois formes de requête atteignent votre application et exigent trois choses différentes. Voici le câblage qui les sert toutes.

Reprenez ceci en entier. Les pièces dépendent les unes des autres, et ces dépendances ne sont pas évidentes.

Le modèle mental

Trois formes de requête atteignent votre application, et chacune exige autre chose :

  • Un visiteur - contenu publié, rendu serveur, statique quand c'est possible. La vitesse, et le CMS hors du chemin de rendu.
  • L'aperçu brouillon (le cookie /api/draft) - contenu brouillon sur la route publique, sans éditeur. Quelqu'un relit un changement, il ne l'édite pas.
  • L'iframe de l'éditeur (cmssyEdit=1 plus un cmssySecret correspondant) - contenu brouillon plus le pont d'édition, sur sa propre route dynamique.

C'est la troisième ligne qui surprend. Une page statique ne voit jamais la chaîne de requête : elle ne peut donc pas savoir qu'on l'édite. D'où l'existence de /cmssy-edit, et tout ce qui suit en découle.

1. Configuration

// cmssy.config.ts
import { defineCmssyConfig } from "@cmssy/next";

export const cmssy = defineCmssyConfig({
  org: process.env.CMSSY_ORG_SLUG,
  workspaceSlug: process.env.CMSSY_WORKSPACE_SLUG,
  draftSecret: process.env.CMSSY_DRAFT_SECRET,
});

Passez process.env brut. Un repli ?? "" transforme une variable manquante en variable vide, et l'erreur ressort plus tard, ailleurs, sans rapport.

Ce module lit l'environnement serveur. N'importez jamais une valeur depuis lui - ni depuis un module qui l'importe - dans un composant "use client". Les types ne posent pas de problème, ils sont effacés. Les valeurs traînent process.env dans le bundle navigateur.

2. Middleware

// proxy.ts
import { createCmssyProxy } from "@cmssy/next/middleware";
import { cmssy } from "@/cmssy.config";

export const proxy = createCmssyProxy(cmssy, {
  // Seulement si vos URL portent la langue (/fr/about) ET que vos routes sont
  // des chemins statiques plutôt qu'une route catch-all.
  stripLocalePrefix: true,
});

// Next l'analyse à la compilation : le matcher doit être un littéral -
// une constante importée est rejetée.
export const config = { matcher: ["/((?!_next/|api/|.*\\..*).*)"] };

Le préréglage résout la langue, envoie le trafic éditeur vérifié vers /cmssy-edit en portant cette langue et le drapeau d'édition, applique la CSP qui autorise l'admin à encadrer votre site, et retire un préfixe de langue si vous l'avez demandé - dans cet ordre.

L'ordre n'est pas un détail, et chaque façon de s'y tromper a déjà été livrée une fois :

  • Résoudre la locale après la réécriture et l'aperçu de l'éditeur s'affiche dans la mauvaise langue - une route ne peut pas lire un préfixe qu'elle ne voit jamais.
  • Oublier le drapeau d'édition et l'en-tête et le pied arrivent comme du balisage que l'éditeur peut sélectionner mais pas remplir.

3. La page publique

Une route catch-all affiche toutes les pages publiées. Les métadonnées viennent d'un helper qui vous appartient, bâti sur l'API de diffusion : le SDK fournit les données, votre application possède ses routes.

// app/[[...path]]/page.tsx
import { createCmssyPage } from "@cmssy/next/server";
import { cmssy } from "@/cmssy/config";
import { blocks } from "@/cmssy/blocks";
import { buildPageMetadata } from "@/services/seo";

export const revalidate = 3600;
export const dynamicParams = true;

export async function generateMetadata({ params }) {
  const { path } = await params;
  // Tel que routé, préfixe compris : le préfixe EST la langue.
  return buildPageMetadata(path);
}

export default createCmssyPage(cmssy, blocks);

buildPageMetadata est à vous, pas au SDK. Il interroge les champs SEO de la page et renvoie un objet Metadata de Next.js - voir SEO pour son contenu.

4. La route d'édition

// app/cmssy-edit/[[...path]]/page.tsx
import { createCmssyEditPage } from "@cmssy/next/server";
import { cmssy } from "@/cmssy.config";
import { blocks } from "@/cmssy/blocks";
import { CmssyEditor } from "@/cmssy/editor";

export const dynamic = "force-dynamic";

export default createCmssyEditPage(cmssy, blocks, { editor: CmssyEditor });

Omettez ce fichier et l'aperçu de l'éditeur reste blanc. C'est la façon la plus courante de casser une application cmssy, et aucun build ne vous préviendra - voir tests.

5. Le pont d'édition

// cmssy/editor.tsx
"use client";
import { CmssyLazyEditor } from "@cmssy/react/client";
import type { CmssyEditorProps } from "@cmssy/next";

export function CmssyEditor(props: CmssyEditorProps) {
  return <CmssyLazyEditor {...props} load={() => import("./blocks")} />;
}

Le registre est chargé paresseusement côté client, si bien que vos loaders de blocs - qui s'exécutent côté serveur et lisent la configuration - n'atteignent jamais le bundle navigateur.

Mise en cache

Publier n'est pas déployer. La route publique met en cache selon son propre revalidate, et cmssy peut appeler un webhook de revalidation à la publication :

export const revalidate = 3600;
export const dynamicParams = true;

La route d'édition fait exception : elle est force-dynamic à dessein, car une page d'édition en cache montrerait le brouillon d'hier.

Étapes suivantes

  • Layouts - en-tête et pied de page comme blocs éditables.
  • Tests - prouver que la route d'édition fonctionne toujours.
  • Comment fonctionne cmssy - ce qui se passe entre la requête et le rendu.