Skip to content

Commit 7292904

Browse files
committed
fix(web): 404 missing build assets instead of serving index.html
The SPA fallback caught /assets/ too, so a browser still running an index.html from before a deploy asked for a chunk hash that no longer existed and got 200 text/html back. The module import then failed on HTML it tried to parse as JavaScript and the app rendered its error page — with nothing in the server logs, because every response was a 200. Reproduced by requesting any nonexistent chunk. Hashed assets now answer 404 when missing, which makes the stale-client case visible rather than disguising it as a broken app, and index.html is marked no-cache so the browser stops pointing at the previous deploy's chunk hashes in the first place. Verified with `nginx -t` against the pinned nginx:1.31-alpine image. Claude-Session: https://claude.ai/code/session_01XvVRm84RrH9APR25g8pFXt
1 parent 2ae4f2d commit 7292904

1 file changed

Lines changed: 21 additions & 0 deletions

File tree

apps/web/nginx/nginx.conf

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,31 @@ http {
2626
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
2727
add_header X-XSS-Protection "1; mode=block" always;
2828

29+
# Hashed build assets are matched before the SPA fallback and answer 404
30+
# when missing.
31+
#
32+
# Without this, `try_files ... /index.html` catches them too: a browser
33+
# still running an index.html from before a deploy asks for a chunk hash
34+
# that no longer exists and gets 200 text/html back. The module import then
35+
# fails on HTML it tried to parse as JavaScript, and the app renders its
36+
# error page — with nothing in the server logs, because every response was
37+
# a 200. A 404 makes the stale-client case visible instead of disguising it
38+
# as a broken app.
39+
location /assets/ {
40+
root /usr/share/nginx/html;
41+
try_files $uri =404;
42+
# Content-hashed filenames, so they can be cached hard.
43+
expires 1y;
44+
add_header Cache-Control "public, immutable";
45+
}
46+
2947
location / {
3048
root /usr/share/nginx/html;
3149
index index.html index.htm;
3250
try_files $uri $uri/ /index.html;
51+
# index.html itself must never be cached, or the browser keeps pointing
52+
# at chunk hashes from the previous deploy.
53+
add_header Cache-Control "no-cache, must-revalidate";
3354
}
3455
}
3556
}

0 commit comments

Comments
 (0)