Show the update banner only when the running build differs from the server and make Refresh UI land the new shell on flaky links

This commit is contained in:
Jonathan Sykes
2026-09-13 17:42:50 +08:00
parent 5fb863ba25
commit 91dab289c3
8 changed files with 526 additions and 266 deletions

View File

@@ -1581,9 +1581,27 @@ app.get('/sw.js', (c) => {
// Static files — serve the frontend/public directory
// Must come AFTER all /api routes so API takes priority
// ============================================================================
app.use('/*', serveStatic({ root: './public' }));
// index.html carries the build tag it belongs to (<meta name="ytp-build">),
// stamped here at request time the same way /sw.js gets it. The page compares
// that against /api/version, so "Update available" only ever shows when the
// running build really differs from the deployed one (see app.js).
let _indexSource = null;
function indexHtml(c) {
if (_indexSource === null) {
try { _indexSource = readFileSync('./public/index.html', 'utf8'); }
catch { return c.text('index.html not found', 404); }
}
return c.html(_indexSource.replace('__BUILD_TAG__', BUILD_TAG), 200, { 'Cache-Control': 'no-cache' });
}
app.get('/', indexHtml);
app.get('/index.html', indexHtml);
// no-cache (revalidate every time) on the shell: the service worker is the
// only cache that should hold app files. With no headers at all, a browser
// may heuristically cache app.js and hand a new worker's install the old one.
app.use('/*', serveStatic({ root: './public', onFound: (_path, c) => { c.header('Cache-Control', 'no-cache'); } }));
// SPA fallback — return index.html for any unmatched path
app.get('/*', serveStatic({ path: './public/index.html' }));
app.get('/*', indexHtml);
// ============================================================================
// Boot