L'une des erreurs de production les plus utiles que j'ai vues après un déploiement avait l'air presque banale :
Failed to load script:
/_next/static/chunks/9253.647385b4be0958e4.js
Elle apparaissait dans le même flux que des échecs d'outils d'analytics, des scripts publicitaires, des messages génériques Script error. et des lectures vidéo interrompues. La plupart de ces événements étaient du bruit. Celui-ci était différent : la ressource qui n'avait pas chargé appartenait à ma propre application Next.js. Si le navigateur ne pouvait réellement pas la récupérer, une partie de la page pouvait cesser de fonctionner.
En revanche, le journal ne disait pas pourquoi le chunk avait échoué. Il pouvait s'agir d'un incident réseau transitoire, d'un problème de proxy ou de CDN, d'un fichier réellement absent, ou encore d'une ancienne page qui continuait à demander un chunk du déploiement précédent alors que le serveur avait déjà remplacé cette version.
Ce dernier scénario est facile à sous-estimer, parce que le nouveau déploiement peut être parfaitement sain. Tous les nouveaux visiteurs chargent la nouvelle version sans problème, tandis qu'un onglet ouvert depuis plusieurs heures reste, en pratique, un client de l'ancienne version.
C'est cette période de coexistence qui m'intéresse ici : pourquoi d'anciens onglets Next.js peuvent casser après un déploiement, comment du HTML périmé et des ressources /_next/static supprimées créent un décalage de version, pourquoi un nettoyage trop agressif aggrave le problème, et comment je concevrais la rétention, le déploiement, l'observabilité et la récupération pour éviter qu'une version réussie ne casse les sessions déjà ouvertes.
Première leçon : un échec de script n'est pas forcément un problème de déploiement
Le flux d'erreurs initial mélangeait plusieurs catégories complètement différentes. Les scripts d'analytics et de publicité tiers peuvent être bloqués par un bloqueur de contenu, un filtre DNS, une fonction de confidentialité, un antivirus, une restriction régionale ou le réseau de l'utilisateur. Une promesse play() peut être interrompue par un pause() ultérieur sans que l'application soit cassée. Et un Script error. générique venant d'une origine externe contient souvent trop peu d'informations pour permettre un diagnostic.
L'échec d'un chunk Next.js de première partie mérite une priorité différente. La séparation utile ressemble plutôt à ceci :
échec d'une ressource tierce
-> généralement télémétrie ou fonction optionnelle dégradée
échec de /_next/static/*.js de l'application
-> du code nécessaire à l'interface peut manquer
Cette distinction compte parce qu'un système d'alerte trop sensible peut noyer les incidents importants sous des centaines de messages sans gravité. Dans mon cas, la ressource qui méritait une enquête était /_next/static/chunks/9253.647385b4be0958e4.js. Le journal prouve que le chargement d'un script de première partie a échoué. Il ne prouve pas que le décalage entre deux déploiements en était la cause.
Je tiens à préserver cette limite : une explication plausible n'est pas une cause établie.
Un onglet ouvert est, de fait, un client d'une ancienne version
Le modèle mental qui m'a permis de mieux comprendre le problème est simple : après un déploiement, plusieurs versions de l'application peuvent continuer à vivre en même temps.
Imaginons que la version A soit en production à 10 h. Un utilisateur ouvre une page et reçoit le HTML ainsi que le JavaScript nécessaire à cette route. À 10 h 30, la version B remplace A. Les nouveaux visiteurs reçoivent B. Mais l'onglet déjà ouvert ne devient pas automatiquement un client B simplement parce que le serveur a changé.
Cet onglet peut encore contenir :
- le runtime JavaScript de la version A ;
- les références de routes et de chunks générées par A ;
- des données de navigation préchargées par A ;
- un état React créé sous A ;
- des modules découpés déjà téléchargés depuis A ;
- des références vers des modules d'A qui n'ont pas encore été téléchargés.
C'est généralement le dernier cas qui rend la panne visible.
Si tous les chunks dont l'utilisateur aura besoin sont déjà dans le cache du navigateur, la session peut continuer sans incident. Mais Next.js découpe le code. Une navigation, un dynamic import, une fenêtre modale, un éditeur ou une fonction utilisée plus tard peuvent nécessiter un fichier JavaScript supplémentaire. Le runtime ancien demande alors une URL qui était valide pour la version A.
Si le serveur conserve cette ressource, tout peut continuer à fonctionner. Si le déploiement l'a supprimée, l'ancien client peut obtenir un 404 alors même que la version B fonctionne parfaitement pour chaque nouvel utilisateur.
Les chunks avec hash de contenu sont faits pour être mis en cache longtemps
Next.js applique volontairement une mise en cache longue aux ressources réellement immuables. La documentation actuelle sur l’auto-hébergement indique que les ressources immuables dont le nom contient un hash SHA sont servies avec une politique d’un an comme celle-ci :
Cache-Control: public, max-age=31536000, immutable
C'est logique : quand le contenu change, l'URL change. Le navigateur n'a donc pas besoin de revalider le fichier à chaque requête.
La conséquence importante est la suivante : l'ancienne URL reste pertinente tant qu'un document ou un runtime ancien peut encore la référencer.
Le fait que le navigateur puisse garder un fichier un an ne sert à rien s'il n'avait jamais téléchargé ce chunk précis avant le déploiement et que l'origine l'a supprimé juste avant que l'utilisateur en ait besoin.
« Les ressources statiques sont immuables » ne veut donc pas dire « on peut supprimer immédiatement les ressources de la version précédente ». L'immutabilité rend leur conservation sûre. Elle n'empêche pas les anciens clients de les demander.
Le guide actuel d'auto-hébergement de Next.js cite explicitement les ressources JavaScript ou CSS manquantes parmi les symptômes possibles d'un décalage de version pendant un déploiement progressif ou multi-serveurs. Le même mécanisme peut apparaître entre un vieil onglet et une origine déjà mise à jour.
Les versions peuvent diverger de plusieurs façons
Dire « c'est un problème de cache » est trop vague pour être utile. Je distingue au moins quatre mécanismes, parce qu'ils n'appellent pas les mêmes corrections.
1. Un ancien onglet demande un chunk qu'il n'avait pas encore chargé
C'est le cas classique d'une session longue. Le document et le runtime viennent d'A. B remplace les fichiers côté serveur. Plus tard, l'utilisateur active une fonction qui nécessite un chunk différé d'A. Si ce fichier a été supprimé, la requête échoue.
2. Du HTML périmé pointe vers des chunks qui n'existent plus
Un CDN, un reverse proxy, un Service Worker, le cache du navigateur ou une couche d'hébergement statique peut conserver du HTML ancien plus longtemps que prévu. Ce HTML référence toujours des ressources de la version A alors que l'origine ne possède plus que B.
Le problème devient particulièrement dangereux si l'on applique par erreur au HTML la même politique longue immutable qu'aux ressources dont le nom contient un hash. Le chunk peut être conservé longtemps parce que son URL versionne son contenu. Le HTML, lui, est précisément l'objet qui détermine quelles URLs appartiennent à la même version cohérente.
3. Un déploiement progressif ou multi-instance mélange les versions
Imaginons deux instances Next.js derrière un load balancer. L'une est déjà en B, l'autre encore en A. Le document peut venir d'une version, puis une navigation ultérieure atterrir sur l'autre. La documentation Next.js actuelle appelle cela décalage de version et cite comme conséquences possibles des ressources manquantes, des Server Functions incompatibles et des échecs de navigation.
Le point de départ le plus sûr est de construire une seule fois et d'exécuter le même artefact sur toutes les instances d'un même déploiement logique. La documentation d'auto-hébergement de Next.js recommande également d'utiliser le même build et un identifiant de build cohérent sur les différents conteneurs plutôt que de reconstruire chaque réplique indépendamment.
4. Le déploiement publie les fichiers dans le mauvais ordre
Même sans vieil onglet, une publication non atomique peut créer temporairement un état impossible :
le nouveau HTML est visible
+
les nouveaux chunks ne sont pas encore disponibles
ou l'inverse :
l'ancien HTML est encore visible
+
les anciens chunks ont déjà été supprimés
Une fenêtre de quelques secondes suffit. Un utilisateur n'a besoin d'y tomber qu'une seule fois.
Le schéma dangereux : tout remplacer et supprimer immédiatement l'ancien arbre
Beaucoup de scripts de déploiement simples commencent par quelque chose comme :
build
rsync --delete new-output/ production/
restart
C'est séduisant parce que le répertoire de production correspond exactement au dernier build. Mais c'est hostile aux clients qui vivent longtemps.
Avec des ressources hashées, les anciens fichiers ne gênent généralement pas les nouveaux : leurs URLs diffèrent. Les supprimer immédiatement économise surtout du stockage. En échange, chaque référence encore valide dans un ancien client devient un 404 potentiel.
Je considère désormais les anciens chunks comme du matériel de compatibilité de déploiement, pas comme des déchets.
Cela ne veut pas dire garder chaque version pour toujours. Le nettoyage doit simplement devenir une politique de rétention distincte et non un effet secondaire de la promotion du dernière version.
La rétention aide, mais aucune durée finie ne règle entièrement le problème
En auto-hébergement, on peut conserver les anciennes ressources /_next/static pendant une période de grâce. La bonne durée dépend de l'usage. Un site où les visiteurs restent deux minutes n'a pas le même profil qu'une application laissée ouverte toute la journée.
Une façon utile de raisonner sur la durée minimale est :
fenêtre de rétention >=
durée plausible de HTML périmé
+ durée réaliste des onglets longue durée
+ fenêtre de rollback
+ marge de propagation du déploiement
Ce n'est pas une garantie mathématique. Un onglet peut rester ouvert plusieurs semaines. Aucune durée finie ne rend ces pannes impossibles.
Je préfère donc une stratégie en plusieurs couches :
- conserver les anciennes ressources immuables assez longtemps pour que les sessions normales continuent ;
- détecter le décalage de version afin de faire passer le client sur la version courante ;
- prévoir une recharge contrôlée en un seul essai ou un chemin de récupération visible lorsque la ressource est réellement absente ;
- surveiller les chunks de première partie manquants pour ajuster la rétention à partir de données réelles.
La rétention évite la majorité des pannes. La récupération traite la longue traîne que toute durée finie laissera forcément subsister.
Ne pas supprimer les anciens chunks avec une simple règle d'âge
Une règle naïve telle que « supprimer tous les fichiers de plus de sept jours » peut également être incorrecte. Une version actuelle peut réutiliser un ancien fichier hashé dont le contenu n'a pas changé. Sa date de modification sur disque est ancienne alors qu'il reste nécessaire.
Une collecte plus robuste est consciente des versions :
- conserver les manifests ou inventaires de ressources de toutes les versions encore dans la fenêtre de compatibilité ;
- calculer l'union des chemins référencés par ces versions ;
- ne jamais supprimer un fichier appartenant à cet ensemble protégé ;
- supprimer uniquement les ressources non référencées après une période de grâce supplémentaire.
Si cette mécanique est trop complexe pour une petite installation, un répertoire statique volontairement plus gros coûte souvent beaucoup moins cher que le diagnostic d'erreurs client rares.
La règle que j'éviterais est simple : ne pas exécuter --delete sur l'arbre partagé /_next/static dans la même opération que celle qui rend la nouvelle version actif.
Next.js possède maintenant une protection explicite contre le décalage de version, mais ce n'est pas un stockage d'anciennes ressources
Next.js actuel permet de configurer deploymentId pour gérer le décalage entre déploiements. Exemple :
// next.config.js
const nextConfig = {
deploymentId: process.env.DEPLOYMENT_VERSION,
}
module.exports = nextConfig
Selon la documentation actuelle de deploymentId, sa configuration amène Next.js à ajouter le paramètre ?dpl=<deploymentId> aux URLs des ressources statiques gérées par le framework, à transporter les informations de déploiement dans les requêtes de navigation côté client et à signaler son identifiant de déploiement dans les réponses du serveur. Lorsqu’il détecte une divergence pendant une navigation, il peut déclencher une navigation complète au lieu de poursuivre une transition douce avec des données incompatibles.
?dpl=<deploymentId>
x-deployment-id
x-nextjs-deployment-id
data-dpl-idC'est utile, mais il ne faut pas lui prêter plus de pouvoir qu'il n'en a. La documentation précise que Next.js n'utilise pas le paramètre entrant ?dpl= pour router vers une ancienne version du serveur. Il sert à invalider le cache. Si une origine auto-hébergée a physiquement supprimé un ancien fichier, une query string ne recrée pas ce fichier.
Je vois donc deploymentId comme un mécanisme de détection et de récupération, pas comme un substitut à une rétention saine des ressources ou à un ordre de publication correct.
Les plateformes d'hébergement peuvent aller plus loin. La documentation actuelle de Vercel sur Skew Protection décrit par exemple un verrouillage de version qui permet aux requêtes gérées par le framework de continuer à viser le déploiement ayant servi le client. C'est une capacité de plateforme, pas quelque chose que je supposerais disponible sur n'importe quel Nginx ou CDN.
Build ID et deployment ID répondent à des problèmes proches, mais distincts
Next.js génère aussi un identifiant de build pendant next build. Si plusieurs conteneurs doivent servir le même déploiement, ils ne devraient pas se transformer discrètement en builds différents parce que chacun a exécuté sa propre compilation.
On peut lier un identifiant déterministe à une version telle qu'un commit Git :
// next.config.js
const nextConfig = {
generateBuildId: async () => process.env.GIT_SHA,
deploymentId: process.env.GIT_SHA,
}
module.exports = nextConfig
Cet exemple est illustratif ; il ne vient pas de mon code de production. La règle d'architecture est plus importante : une version logique devrait correspondre à un artefact cohérent et à une identité de déploiement commune à toutes les instances qui le servent.
generateBuildId identifie le build Next.js. deploymentId est explicitement documenté pour la protection contre le décalage de version et l'invalidation de cache. Les traiter comme des synonymes complique le diagnostic.
Je publierais les ressources avant de basculer les documents vers la nouvelle version
Un ordre de déploiement sûr est volontairement asymétrique. Les nouveaux ressources immuables peuvent exister avant que quiconque les référence. Le nouveau HTML ne devrait jamais apparaître avant que les fichiers qu'il référence soient disponibles.
Conceptuellement, je veux cet ordre :
1. construire la version B une seule fois
2. envoyer les ressources de B dans /_next/static
3. vérifier qu’elles sont réellement récupérables
4. préparer le serveur ou le runtime de B
5. exécuter le health check
6. basculer atomiquement les nouvelles requêtes de documents vers B
7. garder les ressources statiques de A disponibles
8. surveiller B
9. nettoyer les anciennes ressources plus tard
Pour un export statique, le principe est le même : publier d'abord les ressources versionnées, puis le HTML qui les référence. Pour du SSR derrière un reverse proxy, préparer et tester le nouveau serveur avant de déplacer le trafic.
Le retour arrière devrait fonctionner de façon symétrique. Garder le répertoire de la version précédente et ses ressources permet de revenir en arrière sans devoir reconstruire d'anciens fichiers dans l'urgence.
Cela ne rend pas tous les rollbacks sûrs. Une migration de base de données incompatible ou un contrat d'API changé peut empêcher l'ancienne application de fonctionner même si son JavaScript est encore présent. La rétention des ressources ne résout que la partie statique du problème de compatibilité.
Un répertoire partagé de ressources immuables fonctionne bien pour un auto-hébergement simple
Dans une petite installation Nginx, un schéma simple consiste à séparer la version applicative courante d'un stockage partagé pour les ressources versionnés.
Une arborescence illustrative :
/srv/app/releases/2026-08-13-a/
/srv/app/releases/2026-08-13-b/
/srv/app/current -> /srv/app/releases/2026-08-13-b/
/srv/app/shared/_next/static/...
Chaque déploiement ajoute ses nouveaux fichiers /_next/static dans le répertoire partagé sans supprimer ceux des versions encore conservées. Nginx peut servir ce chemin avec une politique immuable :
location ^~ /_next/static/ {
root /srv/app/shared;
add_header Cache-Control "public, max-age=31536000, immutable";
}
Cette configuration est un exemple, pas la description de ma configuration Nginx exacte. En production, il faut tenir compte des permissions, des types MIME, des variantes compressées, du CDN et de la structure de sortie réelle de Next.js.
L'idée importante est le cycle de vie : le pointeur vers la version courante est mutable ; le stockage des ressources hashés est principalement additif.
Le HTML a besoin d'une politique de cache différente de celle des chunks hashés
La manière la plus simple de recréer ce bug est de mettre le HTML en cache comme s'il s'agissait lui-même d'un ressource immuable versionné par son nom.
Pour les pages rendues dynamiquement, Next.js utilise normalement des réponses non réutilisables pour les contenus dynamiques spécifiques à l'utilisateur. Les pages statiques et ISR ont des règles différentes et peuvent être légitimement mises en cache sur un CDN. Dans un export statique servi par Nginx, le comportement dépend encore davantage des en-têtes configurés par l'opérateur.
Je ne pense donc pas en une seule règle de cache pour « le site ». Je sépare les catégories :
ressource hashée dans /_next/static
max-age long
immutable
sûre à conserver
HTML / document de route
doit pouvoir passer à la nouvelle version
politique dépendante du rendu
ne doit pas survivre aux ressources qu’il référence
RSC / navigation / API
règles distinctes de fraîcheur et de compatibilité
Avec un CDN, il peut être nécessaire de purger certaines routes documentaires après un déploiement selon l'architecture. Purger les anciens chunks hashés simplement parce qu'un nouvelle version existe est souvent contre-productif : si l'origine les a également supprimés, on retire peut-être la dernière copie capable de sauver un vieil onglet.
Le guide Next.js sur le cache CDN est utile ici, car il distingue clairement le cache des pages de la politique longue durée appliquée à /_next/static.
Le rechargement automatique est un outil de récupération, pas une stratégie de déploiement
Face à un chunk manquant, la réponse la plus courante est « recharge la page ». Cela fonctionne souvent parce qu'une navigation complète récupère le document courant, qui référence le build courant.
Mais recharger sur n'importe quelle erreur de script crée d'autres problèmes :
- une erreur tierce peut déclencher un rechargement inutile ;
- une panne réelle du serveur peut créer une boucle infinie ;
- un formulaire non enregistré peut perdre son contenu ;
- l'état local des composants React disparaît ;
- une version réellement cassée échouera de nouveau après la recharge.
La documentation Next.js actuelle signale elle-même qu'une navigation complète utilisée pour récupérer d'un décalage de version peut perdre l'état d'un composant comme useState, tandis qu'un état conservé dans l'URL ou le stockage persistant du navigateur peut survivre.
Si j'ajoute une récupération côté client, je la veux ciblée et limitée à une tentative. Exemple illustratif :
const RECOVERY_KEY = 'next-chunk-recovery-attempted'
function isOwnNextAsset(url: string) {
try {
const parsed = new URL(url, window.location.href)
return (
parsed.origin === window.location.origin &&
parsed.pathname.startsWith('/_next/static/')
)
} catch {
return false
}
}
window.addEventListener(
'error',
(event) => {
const target = event.target
if (!(target instanceof HTMLScriptElement)) return
if (!isOwnNextAsset(target.src)) return
reportChunkFailure({
page: window.location.href,
asset: target.src,
})
if (sessionStorage.getItem(RECOVERY_KEY)) return
sessionStorage.setItem(RECOVERY_KEY, '1')
window.location.reload()
},
true,
)
Ce code est volontairement un exemple. En production, il faudrait aussi considérer les chunks CSS, les formes d'erreurs connues du framework, les workflows où une recharge est destructive et la manière d'effacer le marqueur de récupération après un chargement sain.
Dans un éditeur, un checkout ou un long formulaire, je préférerais parfois afficher « Une nouvelle version est disponible ; enregistrez puis rechargez » plutôt que d'imposer immédiatement un rechargement.
La télémétrie doit me dire si je suis réellement face à un décalage de version
Un simple « failed to load script » ne suffit pas. Pour distinguer un ancien chunk supprimé d'un incident réseau aléatoire, il me faut du contexte lié au déploiement.
Les champs utiles comprennent :
- l'URL de la ressource ayant échoué ;
- l'URL de la page courante ;
- le fait que la ressource soit de première partie ou tierce ;
- l'identifiant de version ou de déploiement visible par le client ;
- le navigateur et le système d'exploitation ;
navigator.onLinecomme signal faible, pas comme preuve ;- le temps écoulé depuis le chargement de la page ;
- la proximité avec un déploiement récent ;
- l'existence éventuelle d'une première tentative de récupération ;
- le code HTTP lorsqu'il est observable côté serveur ;
- la version réellement servie par l'origine ou le proxy.
Les motifs deviennent alors beaucoup plus parlants.
Si de nombreux utilisateurs sur des réseaux différents demandent d'anciennes URLs hashées juste après un déploiement et que l'origine répond 404, la suppression prématurée des ressources devient une explication forte. Si un seul utilisateur reçoit une erreur réseau sans réponse HTTP, le décalage de version est beaucoup moins certain. Si le chunk répond 200 avec du HTML ou un mauvais type MIME, le problème vient plutôt du routage ou du proxy.
Je séparerais également les alertes sur les chunks de première partie des erreurs de ressources tierces. C'est le changement le plus directement soutenu par mes logs d'origine : le signal important se trouvait au milieu d'une grande quantité de bruit navigateur.
Le test de reproduction est simple, mais il faut conserver l'ancien onglet
Cette classe de bug échappe facilement aux tests de mise en production habituels parce qu'après un déploiement, les développeurs rechargent presque toujours la page. Ce geste détruit précisément l'état que l'on cherche à tester.
Un meilleur test manuel :
- déployer A ;
- ouvrir un onglet avec un cache navigateur réaliste ;
- n'utiliser qu'une partie de l'application afin de laisser certaines routes ou fonctions différées non chargées ;
- laisser cet onglet ouvert ;
- déployer B ;
- ne pas recharger l'ancien onglet ;
- ouvrir une route ou une fonction dynamique nécessitant du code non encore téléchargé ;
- observer Network et Console ;
- vérifier si les anciennes URLs de ressources répondent encore 200 ;
- vérifier si la détection de décalage de version déclenche une navigation complète contrôlée lorsque c'est nécessaire.
Je répéterais le test avec un CDN, plusieurs instances pendant un rolling deployment et après expiration de la fenêtre de rétention.
Une erreur subtile consiste à activer « Disable cache » dans DevTools pour tout le test. C'est utile pour certaines investigations, mais cela modifie le système. Le scénario d'un onglet longue durée doit aussi être testé avec un cache réaliste.
Conserver les anciens fichiers ne corrige pas tous les échecs de chunk
La rétention est utile précisément parce qu'elle résout un mécanisme bien défini. Elle ne doit pas devenir une nouvelle explication universelle.
Un chunk de première partie peut échouer parce que :
- la requête n'a jamais atteint le serveur ;
- la connexion a été interrompue ;
- une extension navigateur l'a bloquée ;
- un nœud CDN a eu un incident temporaire ;
- Nginx a mal routé le chemin ;
- le serveur a renvoyé une page d'erreur HTML à la place de JavaScript ;
- la compression ou
Content-Encodinga été corrompu ; - les permissions du fichier étaient mauvaises ;
- un déploiement partiel n'a jamais envoyé le chunk ;
- le fichier existait mais a été supprimé trop tôt ;
- le client et le serveur appartenaient à des versions incompatibles.
Le code de réponse et le moment de l'erreur comptent. Un 404 répété sur une ancienne URL hashée après chaque déploiement raconte une histoire très différente d'un ERR_CONNECTION_RESET sur un seul réseau mobile.
C'est pourquoi je ne réécrirais pas mon incident initial en disant « j'ai prouvé que du HTML périmé avait cassé le site ». Je ne l'ai pas prouvé. J'ai observé un véritable échec de chunk de première partie, puis identifié le décalage de version comme un mode de panne sérieux qu'il vaut la peine de prévenir par conception.
Le déploiement le plus sûr considère les anciens clients comme faisant partie de la version
L'erreur conceptuelle la plus profonde consiste à imaginer qu'un déploiement remplace A par B à un instant unique.
Le symlink ou l'orchestrateur peut donner cette impression côté serveur. Mais dans le système complet, des objets A peuvent rester au CDN, des documents A peuvent continuer à s'exécuter dans les navigateurs, A et B peuvent coexister pendant un déploiement progressif, et A peut redevenir courant après un retour arrière.
Le véritable périmètre d'une version est donc un intervalle de temps.
Mes règles de déploiement Next.js découlent désormais de cette idée :
- Construire une seule fois par version logique. Les répliques ne doivent pas produire silencieusement des builds différents.
- Publier les ressources immuables avant les documents qui les référencent.
- Conserver les anciennes ressources hashés pendant une fenêtre de compatibilité volontaire.
- Ne pas donner au HTML mutable la même politique de cache qu'aux chunks hashés.
- Utiliser
deploymentIdquand le modèle de déploiement peut produire du décalage de version. - Utiliser la protection de plateforme uniquement lorsque l'hébergeur fournit réellement un routage conscient de la version.
- Rendre la récupération unique et consciente de l'état utilisateur.
- Surveiller séparément les échecs de chunks de première partie.
- Tester chaque déploiement avec un vieil onglet encore ouvert.
- Nettoyer les anciennes ressources plus tard, pas pendant la promotion.
La règle que j'applique maintenant
Un build vert et une page fraîchement chargée qui fonctionne ne prouvent pas qu'un déploiement est sûr pour les utilisateurs qui étaient déjà présents.
L'ancien onglet n'est pas un déchet. C'est un vrai client qui exécute une vraie version précédente.
Une fois ce modèle adopté, les erreurs de chunks deviennent beaucoup moins mystérieuses. Un hash de contenu donne une identité stable à une ressource. Un cache longue durée rend cette identité efficace. Mais le déploiement doit respecter cette identité assez longtemps, ou offrir au client un moyen contrôlé de passer à la version suivante.
Je n'ai pas besoin de garder chaque ancienne version actif pour toujours. J'ai besoin que le système survive à la période où anciens clients et nouveaux serveurs coexistent légitimement.
Voilà le contrat de déploiement qui m'importe désormais : les nouveaux utilisateurs reçoivent la nouvelle version, les anciens ne perdent pas les fichiers que leur version sait encore demander, et tout décalage restant aboutit à une récupération volontaire plutôt qu'à une page cassée.