Régénération Statique Incrémentielle

Exemples

Next.js vous permet de créer ou mettre à jour des pages statiques après avoir construit votre site. La Régénération Statique Incrémentielle (ISR) vous permet d'utiliser la génération statique page par page, sans avoir à reconstruire l'intégralité du site. Avec ISR, vous conservez les avantages du statique tout en pouvant passer à l'échelle pour des millions de pages.

Bon à savoir : Le runtime edge n'est actuellement pas compatible avec ISR, bien que vous puissiez exploiter stale-while-revalidate en définissant manuellement l'en-tête cache-control.

Pour utiliser ISR, ajoutez la propriété revalidate à getStaticProps :

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

// Cette fonction est appelée au moment du build côté serveur.
// Elle peut être rappelée, sur une fonction serverless, si
// la revalidation est activée et qu'une nouvelle requête arrive
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js tentera de régénérer la page :
    // - Lorsqu'une requête arrive
    // - Au maximum une fois toutes les 10 secondes
    revalidate: 10, // En secondes
  }
}

// Cette fonction est appelée au moment du build côté serveur.
// Elle peut être rappelée, sur une fonction serverless, si
// le chemin n'a pas été généré.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Obtenir les chemins à pré-rendre basés sur les posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // Nous pré-rendrons uniquement ces chemins au moment du build.
  // { fallback: 'blocking' } rendra les pages côté serveur
  // à la demande si le chemin n'existe pas.
  return { paths, fallback: 'blocking' }
}

export default Blog

Lorsqu'une requête est faite vers une page pré-rendue au moment du build, elle affichera initialement la page mise en cache.

  • Toutes les requêtes vers la page après la requête initiale et avant 10 secondes sont également mises en cache et instantanées.
  • Après la fenêtre de 10 secondes, la prochaine requête affichera toujours la page en cache (obsolète)
  • Next.js déclenche une régénération de la page en arrière-plan.
  • Une fois la page générée avec succès, Next.js invalidera le cache et affichera la page mise à jour. Si la régénération en arrière-plan échoue, l'ancienne page restera inchangée.

Lorsqu'une requête est faite vers un chemin qui n'a pas été généré, Next.js rendra la page côté serveur pour la première requête. Les requêtes futures serviront le fichier statique depuis le cache. ISR sur Vercel persiste le cache globalement et gère les rollbacks.

Bon à savoir : Vérifiez si votre fournisseur de données en amont a la mise en cache activée par défaut. Vous devrez peut-être la désactiver (par exemple useCdn: false), sinon une revalidation ne pourra pas récupérer de nouvelles données pour mettre à jour le cache ISR. La mise en cache peut se produire au niveau d'un CDN (pour un endpoint demandé) lorsqu'il retourne l'en-tête Cache-Control.

Revalidation à la Demande

Si vous définissez un temps revalidate de 60, tous les visiteurs verront la même version générée de votre site pendant une minute. La seule façon d'invalider le cache est qu'un visiteur accède à cette page après que la minute soit passée.

À partir de v12.2.0, Next.js prend en charge la Régénération Statique Incrémentielle à la Demande pour purger manuellement le cache Next.js d'une page spécifique. Cela facilite la mise à jour de votre site lorsque :

  • Du contenu de votre CMS headless est créé ou mis à jour
  • Les métadonnées e-commerce changent (prix, description, catégorie, avis, etc.)

Dans getStaticProps, vous n'avez pas besoin de spécifier revalidate pour utiliser la revalidation à la demande. Si revalidate est omis, Next.js utilisera la valeur par défaut false (pas de revalidation) et ne revalidera la page qu'à la demande lorsque revalidate() est appelé.

Bon à savoir : Le Middleware ne sera pas exécuté pour les requêtes ISR à la demande. Appelez plutôt revalidate() sur le chemin exact que vous souhaitez revalider. Par exemple, si vous avez pages/blog/[slug].js et une réécriture de /post-1 vers /blog/post-1, vous devrez appeler res.revalidate('/blog/post-1').

Utilisation de la Revalidation à la Demande

D'abord, créez un jeton secret connu uniquement par votre application Next.js. Ce secret sera utilisé pour empêcher un accès non autorisé à la route API de revalidation. Vous pouvez accéder à la route (manuellement ou via un webhook) avec l'URL suivante :

Terminal
https://<your-site.com>/api/revalidate?secret=<token>

Ensuite, ajoutez le secret comme Variable d'Environnement à votre application. Enfin, créez la route API de revalidation :

pages/api/revalidate.js
export default async function handler(req, res) {
  // Vérifier le secret pour confirmer que c'est une requête valide
  if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
    return res.status(401).json({ message: 'Token invalide' })
  }

  try {
    // ce devrait être le chemin réel et non un chemin réécrit
    // par exemple pour "/blog/[slug]" ce devrait être "/blog/post-1"
    await res.revalidate('/path-to-revalidate')
    return res.json({ revalidated: true })
  } catch (err) {
    // S'il y a une erreur, Next.js continuera
    // à afficher la dernière page générée avec succès
    return res.status(500).send('Erreur lors de la revalidation')
  }
}

Voir notre démo pour voir la revalidation à la demande en action et donner votre feedback.

Tester l'ISR à la Demande pendant le développement

Lors de l'exécution locale avec next dev, getStaticProps est appelé à chaque requête. Pour vérifier que votre configuration ISR à la demande est correcte, vous devrez créer un build de production et démarrer le serveur de production :

Terminal
$ next build
$ next start

Ensuite, vous pouvez confirmer que les pages statiques ont bien été revalidées.

Gestion des Erreurs et Revalidation

S'il y a une erreur dans getStaticProps lors de la régénération en arrière-plan, ou si vous lancez une erreur manuellement, la dernière page générée avec succès continuera d'être affichée. Lors de la prochaine requête, Next.js réessayera d'appeler getStaticProps.

export async function getStaticProps() {
  // Si cette requête lance une erreur non capturée, Next.js ne
  // invalidera pas la page actuellement affichée et
  // réessayera getStaticProps à la prochaine requête.
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  if (!res.ok) {
    // S'il y a une erreur serveur, vous pourriez vouloir
    // lancer une erreur au lieu de retourner pour que le cache ne soit pas mis à jour
    // jusqu'à la prochaine requête réussie.
    throw new Error(`Échec de la récupération des posts, statut reçu ${res.status}`)
  }

  // Si la requête a réussi, retournez les posts
  // et revalidez toutes les 10 secondes.
  return {
    props: {
      posts,
    },
    revalidate: 10,
  }
}

Auto-hébergement de l'ISR

La Régénération Statique Incrémentielle (ISR) fonctionne sur les sites Next.js auto-hébergés dès que vous utilisez next start.

Vous pouvez utiliser cette approche lors d'un déploiement sur des orchestrateurs de conteneurs comme Kubernetes ou HashiCorp Nomad. Par défaut, les assets générés seront stockés en mémoire sur chaque pod. Cela signifie que chaque pod aura sa propre copie des fichiers statiques. Des données obsolètes peuvent être affichées jusqu'à ce qu'une requête atteigne ce pod spécifique.

Pour garantir la cohérence entre tous les pods, vous pouvez désactiver la mise en cache en mémoire. Cela indiquera au serveur Next.js de n'utiliser que les assets générés par ISR dans le système de fichiers.

Vous pouvez utiliser un montage réseau partagé dans vos pods Kubernetes (ou une configuration similaire) pour réutiliser le même cache de système de fichiers entre différents conteneurs. En partageant le même montage, le dossier .next qui contient le cache next/image sera également partagé et réutilisé.

Pour désactiver la mise en cache en mémoire, définissez isrMemoryCacheSize à 0 dans votre fichier next.config.js :

next.config.js
module.exports = {
  experimental: {
    // Par défaut à 50MB
    isrMemoryCacheSize: 0, // taille du cache en octets
  },
}

Bon à savoir : Vous pourriez avoir à considérer une condition de course entre plusieurs pods essayant de mettre à jour le cache simultanément, selon la configuration de votre montage partagé.

Historique des Versions

VersionChangements
v12.2.0L'ISR à la Demande est stable
v12.1.0L'ISR à la Demande ajoutée (bêta).
v12.0.0Fallback ISR conscient des bots ajouté.
v9.5.0Base Path ajouté.