fix(cache): serve HTML with no-store so deploys reach browsers without a hard refresh
Browsers were serving a cached old home.html on normal reloads (only incognito/ hard-refresh got the new one). HTML now sends Cache-Control: no-store; versioned assets keep ETag revalidation. Bumps build marker to push4. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -589,7 +589,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="/icons.js?v=3"></script>
|
<script src="/icons.js?v=3"></script>
|
||||||
<script>window.__BUILD='2026-06-24-push3';console.log('%cBizGaze Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);</script>
|
<script>window.__BUILD='2026-06-24-push4';console.log('%cBizGaze Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);</script>
|
||||||
<div class="loading" id="loading">Loading…</div>
|
<div class="loading" id="loading">Loading…</div>
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
|
|||||||
+10
-3
@@ -23,15 +23,22 @@ function serveStatic(req, res) {
|
|||||||
// tiny 304 (no re-download) when nothing changed — fast reloads, but always fresh on edits.
|
// tiny 304 (no re-download) when nothing changed — fast reloads, but always fresh on edits.
|
||||||
fs.stat(fp, (serr, st) => {
|
fs.stat(fp, (serr, st) => {
|
||||||
if (serr || !st.isFile()) return json(res, 404, { error: 'not found' });
|
if (serr || !st.isFile()) return json(res, 404, { error: 'not found' });
|
||||||
const ct = MIME[path.extname(fp)] || 'application/octet-stream';
|
const ext = path.extname(fp);
|
||||||
|
const ct = MIME[ext] || 'application/octet-stream';
|
||||||
|
// HTML entry pages are NEVER cached (no-store) so a deploy reaches every browser on the
|
||||||
|
// next load — no hard-refresh needed. Versioned assets (e.g. icons.js?v=) still revalidate
|
||||||
|
// cheaply via ETag/304.
|
||||||
|
const isHtml = ext === '.html';
|
||||||
const etag = '"' + st.size.toString(16) + '-' + Math.round(st.mtimeMs).toString(16) + '"';
|
const etag = '"' + st.size.toString(16) + '-' + Math.round(st.mtimeMs).toString(16) + '"';
|
||||||
if (req.headers['if-none-match'] === etag) {
|
if (!isHtml && req.headers['if-none-match'] === etag) {
|
||||||
res.writeHead(304, { ETag: etag, 'Cache-Control': 'no-cache' });
|
res.writeHead(304, { ETag: etag, 'Cache-Control': 'no-cache' });
|
||||||
return res.end();
|
return res.end();
|
||||||
}
|
}
|
||||||
fs.readFile(fp, (err, data) => {
|
fs.readFile(fp, (err, data) => {
|
||||||
if (err) return json(res, 404, { error: 'not found' });
|
if (err) return json(res, 404, { error: 'not found' });
|
||||||
res.writeHead(200, { 'Content-Type': ct, 'Cache-Control': 'no-cache', ETag: etag, 'Content-Length': st.size });
|
const headers = { 'Content-Type': ct, 'Content-Length': st.size, 'Cache-Control': isHtml ? 'no-store, must-revalidate' : 'no-cache' };
|
||||||
|
if (!isHtml) headers.ETag = etag;
|
||||||
|
res.writeHead(200, headers);
|
||||||
res.end(data);
|
res.end(data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user