fix: prevent stale chunk errors after deployments
- Set Cache-Control no-cache on index.html in nginx so browsers always fetch fresh chunk references after a deploy - Auto-reload on chunk load failures (stale deploy detection) with loop prevention via sessionStorage - Show friendly "App Updated" message if auto-reload doesn't resolve it Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,12 +8,19 @@ server {
|
|||||||
gzip on;
|
gzip on;
|
||||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||||
|
|
||||||
|
# index.html — never cache (so deploys serve new chunk references)
|
||||||
|
location = /index.html {
|
||||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||||
|
add_header Pragma "no-cache";
|
||||||
|
add_header Expires "0";
|
||||||
|
}
|
||||||
|
|
||||||
# Handle SPA routing - serve index.html for all routes
|
# Handle SPA routing - serve index.html for all routes
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Cache static assets
|
# Cache hashed static assets (immutable — filenames change on rebuild)
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||||
expires 1y;
|
expires 1y;
|
||||||
add_header Cache-Control "public, immutable";
|
add_header Cache-Control "public, immutable";
|
||||||
|
|||||||
@@ -1,14 +1,44 @@
|
|||||||
|
import { useEffect } from 'react'
|
||||||
import { useRouteError, isRouteErrorResponse, useNavigate } from 'react-router-dom'
|
import { useRouteError, isRouteErrorResponse, useNavigate } from 'react-router-dom'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
function isChunkLoadError(error: unknown): boolean {
|
||||||
|
if (!(error instanceof Error)) return false
|
||||||
|
const msg = error.message.toLowerCase()
|
||||||
|
return (
|
||||||
|
msg.includes('failed to fetch dynamically imported module') ||
|
||||||
|
msg.includes('importing a module script failed') ||
|
||||||
|
msg.includes('loading chunk') ||
|
||||||
|
msg.includes('loading css chunk')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const RELOAD_KEY = 'rf_chunk_reload'
|
||||||
|
|
||||||
export function RouteError() {
|
export function RouteError() {
|
||||||
const error = useRouteError()
|
const error = useRouteError()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
// Auto-reload once on chunk load failures (stale deploy)
|
||||||
|
useEffect(() => {
|
||||||
|
if (isChunkLoadError(error)) {
|
||||||
|
const lastReload = sessionStorage.getItem(RELOAD_KEY)
|
||||||
|
const now = Date.now()
|
||||||
|
// Only auto-reload if we haven't reloaded in the last 10 seconds (prevent loops)
|
||||||
|
if (!lastReload || now - Number(lastReload) > 10_000) {
|
||||||
|
sessionStorage.setItem(RELOAD_KEY, String(now))
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [error])
|
||||||
|
|
||||||
let errorMessage = 'An unexpected error occurred'
|
let errorMessage = 'An unexpected error occurred'
|
||||||
let errorDetails = ''
|
let errorDetails = ''
|
||||||
|
|
||||||
if (isRouteErrorResponse(error)) {
|
if (isChunkLoadError(error)) {
|
||||||
|
errorMessage = 'App Updated'
|
||||||
|
errorDetails = 'A new version was deployed. Please refresh the page.'
|
||||||
|
} else if (isRouteErrorResponse(error)) {
|
||||||
errorMessage = error.status === 404 ? 'Page not found' : `Error ${error.status}`
|
errorMessage = error.status === 404 ? 'Page not found' : `Error ${error.status}`
|
||||||
errorDetails = error.statusText || ''
|
errorDetails = error.statusText || ''
|
||||||
} else if (error instanceof Error) {
|
} else if (error instanceof Error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user