Mode brouillon

Le rendu statique est utile lorsque vos pages récupèrent des données depuis un CMS headless. Cependant, il n'est pas idéal lorsque vous rédigez un brouillon sur votre CMS headless et que vous souhaitez le visualiser immédiatement sur votre page. Vous voudriez que Next.js rende ces pages au moment de la requête plutôt qu'au moment de la construction, et qu'il récupère le contenu du brouillon plutôt que le contenu publié. Vous voudriez que Next.js bascule vers un rendu dynamique uniquement pour ce cas spécifique.

Next.js propose une fonctionnalité appelée Mode brouillon qui résout ce problème. Voici comment l'utiliser.

Étape 1 : Créer et accéder au gestionnaire de route

Commencez par créer un gestionnaire de route. Il peut porter n'importe quel nom, par exemple app/api/draft/route.ts.

Ensuite, importez draftMode depuis next/headers et appelez la méthode enable().

// gestionnaire de route activant le mode brouillon
import { draftMode } from 'next/headers'

export async function GET(request: Request) {
  draftMode().enable()
  return new Response('Le mode brouillon est activé')
}
// gestionnaire de route activant le mode brouillon
import { draftMode } from 'next/headers'

export async function GET(request) {
  draftMode().enable()
  return new Response('Le mode brouillon est activé')
}

Cela définira un cookie pour activer le mode brouillon. Les requêtes suivantes contenant ce cookie déclencheront le Mode brouillon, modifiant ainsi le comportement des pages générées statiquement (nous y reviendrons plus tard).

Vous pouvez tester cela manuellement en visitant /api/draft et en inspectant les outils de développement de votre navigateur. Notez l'en-tête de réponse Set-Cookie avec un cookie nommé __prerender_bypass.

Accès sécurisé depuis votre CMS headless

En pratique, vous voudrez appeler ce gestionnaire de route de manière sécurisée depuis votre CMS headless. Les étapes précises varieront selon le CMS headless utilisé, mais voici quelques étapes courantes.

Ces étapes supposent que votre CMS headless prend en charge la configuration d'URLs de brouillon personnalisées. Si ce n'est pas le cas, vous pouvez toujours utiliser cette méthode pour sécuriser vos URLs de brouillon, mais vous devrez construire et accéder à l'URL de brouillon manuellement.

Premièrement, créez un jeton secret en utilisant un générateur de jetons de votre choix. Ce secret ne sera connu que par votre application Next.js et votre CMS headless. Il empêchera les personnes n'ayant pas accès à votre CMS d'accéder aux URLs de brouillon.

Deuxièmement, si votre CMS headless prend en charge les URLs de brouillon personnalisées, spécifiez l'URL suivante comme URL de brouillon. Cela suppose que votre gestionnaire de route se trouve dans app/api/draft/route.ts.

Terminal
https://<votre-site>/api/draft?secret=<jeton>&slug=<chemin>
  • <votre-site> doit être votre domaine de déploiement.
  • <jeton> doit être remplacé par le jeton secret que vous avez généré.
  • <chemin> doit être le chemin de la page que vous souhaitez visualiser. Si vous voulez voir /posts/foo, utilisez &slug=/posts/foo.

Votre CMS headless pourrait vous permettre d'inclure une variable dans l'URL de brouillon pour que <chemin> soit défini dynamiquement en fonction des données du CMS, comme ceci : &slug=/posts/{entry.fields.slug}.

Enfin, dans le gestionnaire de route :

  • Vérifiez que le secret correspond et que le paramètre slug existe (sinon, la requête doit échouer).
  • Appelez draftMode.enable() pour définir le cookie.
  • Redirigez ensuite le navigateur vers le chemin spécifié par slug.
// gestionnaire de route avec secret et slug
import { draftMode } from 'next/headers'
import { redirect } from 'next/navigation'

export async function GET(request: Request) {
  // Analyse des paramètres de la chaîne de requête
  const { searchParams } = new URL(request.url)
  const secret = searchParams.get('secret')
  const slug = searchParams.get('slug')

  // Vérification du secret et des paramètres
  // Ce secret ne doit être connu que par ce gestionnaire de route et le CMS
  if (secret !== 'MY_SECRET_TOKEN' || !slug) {
    return new Response('Jeton invalide', { status: 401 })
  }

  // Interrogez le CMS headless pour vérifier si le `slug` fourni existe
  // getPostBySlug implémenterait la logique de récupération nécessaire vers le CMS headless
  const post = await getPostBySlug(slug)

  // Si le slug n'existe pas, empêchez l'activation du mode brouillon
  if (!post) {
    return new Response('Slug invalide', { status: 401 })
  }

  // Activez le mode brouillon en définissant le cookie
  draftMode().enable()

  // Redirigez vers le chemin du post récupéré
  // Nous ne redirigeons pas vers searchParams.slug pour éviter les vulnérabilités de redirection ouverte
  redirect(post.slug)
}
// gestionnaire de route avec secret et slug
import { draftMode } from 'next/headers'
import { redirect } from 'next/navigation'

export async function GET(request) {
  // Analyse des paramètres de la chaîne de requête
  const { searchParams } = new URL(request.url)
  const secret = searchParams.get('secret')
  const slug = searchParams.get('slug')

  // Vérification du secret et des paramètres
  // Ce secret ne doit être connu que par ce gestionnaire de route et le CMS
  if (secret !== 'MY_SECRET_TOKEN' || !slug) {
    return new Response('Jeton invalide', { status: 401 })
  }

  // Interrogez le CMS headless pour vérifier si le `slug` fourni existe
  // getPostBySlug implémenterait la logique de récupération nécessaire vers le CMS headless
  const post = await getPostBySlug(slug)

  // Si le slug n'existe pas, empêchez l'activation du mode brouillon
  if (!post) {
    return new Response('Slug invalide', { status: 401 })
  }

  // Activez le mode brouillon en définissant le cookie
  draftMode().enable()

  // Redirigez vers le chemin du post récupéré
  // Nous ne redirigeons pas vers searchParams.slug pour éviter les vulnérabilités de redirection ouverte
  redirect(post.slug)
}

Si cela réussit, le navigateur sera redirigé vers le chemin que vous souhaitez visualiser avec le cookie de mode brouillon.

Étape 2 : Mettre à jour la page

L'étape suivante consiste à mettre à jour votre page pour vérifier la valeur de draftMode().isEnabled.

Si vous demandez une page avec le cookie défini, les données seront récupérées au moment de la requête (au lieu du moment de la construction).

De plus, la valeur de isEnabled sera true.

// page qui récupère des données
import { draftMode } from 'next/headers'

async function getData() {
  const { isEnabled } = draftMode()

  const url = isEnabled
    ? 'https://draft.example.com'
    : 'https://production.example.com'

  const res = await fetch(url)

  return res.json()
}

export default async function Page() {
  const { title, desc } = await getData()

  return (
    <main>
      <h1>{title}</h1>
      <p>{desc}</p>
    </main>
  )
}
// page qui récupère des données
import { draftMode } from 'next/headers'

async function getData() {
  const { isEnabled } = draftMode()

  const url = isEnabled
    ? 'https://draft.example.com'
    : 'https://production.example.com'

  const res = await fetch(url)

  return res.json()
}

export default async function Page() {
  const { title, desc } = await getData()

  return (
    <main>
      <h1>{title}</h1>
      <p>{desc}</p>
    </main>
  )
}

C'est tout ! Si vous accédez au gestionnaire de route de brouillon (avec secret et slug) depuis votre CMS headless ou manuellement, vous devriez maintenant pouvoir voir le contenu du brouillon. Et si vous mettez à jour votre brouillon sans le publier, vous devriez pouvoir visualiser les modifications.

Définissez cette URL comme URL de brouillon sur votre CMS headless ou accédez-y manuellement, et vous devriez pouvoir voir le brouillon.

Terminal
https://<votre-site>/api/draft?secret=<jeton>&slug=<chemin>

Plus de détails

Par défaut, la session du mode brouillon se termine lorsque le navigateur est fermé.

Pour effacer manuellement le cookie du mode brouillon, créez un gestionnaire de route qui appelle draftMode().disable() :

import { draftMode } from 'next/headers'

export async function GET(request: Request) {
  draftMode().disable()
  return new Response('Le mode brouillon est désactivé')
}
import { draftMode } from 'next/headers'

export async function GET(request) {
  draftMode().disable()
  return new Response('Le mode brouillon est désactivé')
}

Envoyez ensuite une requête à /api/disable-draft pour invoquer le gestionnaire de route. Si vous appelez cette route en utilisant next/link, vous devez passer prefetch={false} pour éviter de supprimer accidentellement le cookie lors du préchargement.

Unique par next build

Une nouvelle valeur de cookie de contournement sera générée à chaque exécution de next build.

Cela garantit que le cookie de contournement ne peut pas être deviné.

Bon à savoir : Pour tester le mode brouillon localement via HTTP, votre navigateur devra autoriser les cookies tiers et l'accès au stockage local.