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

Afficher le contenu cmssy dans votre app

Une seule route catch-all transforme chaque page publiée - blocs, layout, SEO et langue - en HTML rendu côté serveur sur votre propre frontend Next.js.

Rendu

La route catch-all, le composant de page, les métadonnées, le layout, le routage localisé et la revalidation ISR.

Last updated: 24 juillet 2026

La route catch-all

Un workspace cmssy stocke le contenu ; votre app le rend. Une route catch-all optionnelle - app/[[...path]]/page.tsx - associe chaque slug publié (et son préfixe de langue) à une page. createCmssyPage récupère la page pour le chemin courant, associe chaque bloc à votre composant enregistré et le rend côté serveur.

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

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

const renderPage = createCmssyPage(cmssy, blocks);

type PageProps = { params: Promise<{ path?: string[] }> };

export async function generateMetadata({ params }: PageProps) {
  return buildCmssyMetadata(cmssy, (await params).path);
}

export default function Page({ params }: PageProps) {
  return renderPage({ params });
}

La route catch-all est rendue statiquement : elle ne lit jamais searchParams ni headers(), donc l'ISR reste actif. L'aperçu des brouillons fonctionne toujours par requête via draftMode().


Composant de page & configuration

createCmssyPage(config, blocks, options?) renvoie un composant serveur asynchrone. config provient de defineCmssyConfig ; blocks est le tableau des définitions defineBlock que le SDK associe par type. Passez { editor } pour monter l'éditeur visuel sur la route d'aperçu, ou { path } pour fixer une route mono-page.

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

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

Métadonnées & SEO

buildCmssyMetadata(config, path, options?) renvoie un objet Metadata Next.js complet à partir des champs SEO de la page et du branding du workspace : titre, description, mots-clés, canonique ainsi que les alternatives hreflang par langue, et les cartes Open Graph / Twitter. Appelez-le dans generateMetadata (voir la route ci-dessus).

Passez le chemin catch-all tel que routé - préfixe de langue compris. Le préfixe indique au SDK quelle langue rendre ; le retirer d'abord fait hériter chaque traduction du titre de la langue par défaut et d'une canonique pointant vers l'URL par défaut, ce qui indique aux moteurs de recherche que la traduction est un doublon.

buildCmssyMetadata(cmssy, path, {
  image: "https://assets.cmssy.io/og.png",
  ogType: "article",
});

Header & footer

Les régions partagées - header, footer - sont des blocs de layout. Rendez-les dans app/[[...path]]/layout.tsx : fetchLayouts récupère les groupes de layout, CmssyServerLayout rend une position, et CmssyLocaleProvider expose la langue active aux blocs client.

// app/[[...path]]/layout.tsx
import { fetchLayouts, resolveSiteLocales, CmssyServerLayout } from "@cmssy/react";
import { splitCmssyLocale } from "@cmssy/core";
import { CmssyLocaleProvider } from "@cmssy/next/client";
import { blocks } from "@/cmssy/blocks";
import { cmssy } from "@/cmssy/config";

export default async function Layout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: Promise<{ path?: string[] }>;
}) {
  const { path } = await params;
  const [{ locale }, siteLocales, groups] = await Promise.all([
    splitCmssyLocale(cmssy, path),
    resolveSiteLocales(cmssy),
    fetchLayouts(cmssy, "/"),
  ]);

  const slot = (position: "header" | "footer") => (
    <CmssyServerLayout
      groups={groups}
      blocks={blocks}
      position={position}
      locale={locale}
      defaultLocale={siteLocales.defaultLocale}
      enabledLocales={siteLocales.locales}
    />
  );

  return (
    <html lang={locale}>
      <body>
        <CmssyLocaleProvider
          value={{
            current: locale,
            default: siteLocales.defaultLocale,
            enabled: siteLocales.locales,
          }}
        >
          {slot("header")}
          {children}
          {slot("footer")}
        </CmssyLocaleProvider>
      </body>
    </html>
  );
}

Routage localisé

cmssy encode la langue en préfixe de chemin : /about est la langue par défaut, /pl/about est le polonais. La même route catch-all gère les deux. splitCmssyLocale(config, path) lit les langues activées du workspace et sépare le préfixe du reste - sans requête ni en-têtes, donc compatible statique.

const { locale, path: rest } = await splitCmssyLocale(cmssy, path);
// ["pl", "about"]  ->  locale "pl", rest ["about"]
// ["about"]        ->  locale "en" (default), rest ["about"]

ISR & revalidation à la demande

Les pages publiées sont mises en cache et régénérées par l'ISR via export const revalidate. Pour rafraîchir instantanément à la publication, ajoutez une route à la demande et pointez-y le webhook content.changed du workspace. cmssy envoie en POST le path modifié ; la route le revalide, ou tout le site (portée layout) si aucun chemin n'est envoyé. Protégez-la avec un secret partagé.

// app/api/revalidate/route.ts
import { revalidatePath } from "next/cache";
import { NextResponse, type NextRequest } from "next/server";

export async function POST(request: NextRequest) {
  const secret = process.env.CMSSY_REVALIDATE_SECRET;
  const provided =
    request.nextUrl.searchParams.get("secret") ??
    request.headers.get("x-revalidate-secret");
  if (!secret || provided !== secret) {
    return NextResponse.json({ revalidated: false }, { status: 401 });
  }

  const { path } = (await request.json().catch(() => ({}))) as { path?: string };
  if (path) revalidatePath(path);
  else revalidatePath("/", "layout");

  return NextResponse.json({ revalidated: true, path: path ?? "/" });
}

Prochaines étapes

Rendu - Cmssy Headless SDK