mirror of
https://github.com/guyg1474/hcrb.git
synced 2026-10-15 23:13:28 +02:00
CSS/JS mit Versionsnummer ausliefern, damit nach Updates kein alter Cache greift
Der Nginx Proxy Manager ("Cache Assets") und Browser hielten das alte
common.js vor, die neue Startseite brach mit fehlendem Export ab.
HTML und JS werden jetzt mit no-cache ausgeliefert, CSS/JS-Adressen und
Modul-Importe bekommen ?v=<Prüfsumme> angehängt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
486e6f6784
commit
f46016487d
1 file changed
+45
-3
@@ -1,7 +1,7 @@
|
||||
import express from 'express';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { readFileSync, writeFileSync, renameSync, mkdirSync, existsSync, unlinkSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { randomUUID, createHash } from 'node:crypto';
|
||||
import { readFileSync, writeFileSync, renameSync, mkdirSync, existsSync, unlinkSync, readdirSync, statSync } from 'node:fs';
|
||||
import { dirname, join, extname, normalize, sep } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { authRoutes, requireAuth } from './auth.js';
|
||||
|
||||
@@ -178,6 +178,46 @@ function findOr404(list, id, res, what) {
|
||||
return item;
|
||||
}
|
||||
|
||||
// ---------- Versionierte Seiten ----------
|
||||
// Proxys (z. B. Nginx Proxy Manager mit "Cache Assets") und Browser halten CSS/JS lange vor. Damit nach einem
|
||||
// Update nie alte Dateien mit neuen gemischt werden, hängt der Server an jede CSS/JS-Adresse in HTML und an
|
||||
// jeden Modul-Import ?v=<Prüfsumme aller CSS/JS-Dateien> an. HTML und JS selbst werden immer neu geprüft.
|
||||
const ASSET_DIRS = ['public/css', 'public/js', 'private/js'].map((d) => join(ROOT, d));
|
||||
let assetVersion = { key: '', value: '' };
|
||||
|
||||
function currentAssetVersion() {
|
||||
const files = ASSET_DIRS.flatMap((dir) => (existsSync(dir) ? readdirSync(dir).map((f) => join(dir, f)) : []))
|
||||
.filter((f) => /\.(css|js)$/.test(f)).sort();
|
||||
// Nur neu rechnen, wenn sich Dateien geändert haben (Änderungszeit + Größe)
|
||||
const key = files.map((f) => { const st = statSync(f); return `${f}:${st.mtimeMs}:${st.size}`; }).join('|');
|
||||
if (key !== assetVersion.key) {
|
||||
const hash = createHash('sha1');
|
||||
for (const f of files) hash.update(readFileSync(f));
|
||||
assetVersion = { key, value: hash.digest('hex').slice(0, 10) };
|
||||
}
|
||||
return assetVersion.value;
|
||||
}
|
||||
|
||||
function versioned(dir, cacheControl) {
|
||||
return (req, res, next) => {
|
||||
if (req.method !== 'GET' && req.method !== 'HEAD') return next();
|
||||
let path;
|
||||
try { path = decodeURIComponent(req.path); } catch { return next(); }
|
||||
if (path.endsWith('/')) path += 'index.html';
|
||||
let file = normalize(join(dir, path));
|
||||
if (!file.startsWith(dir + sep)) return next();
|
||||
if (!extname(file)) file += '.html';
|
||||
if (!/\.(html|js)$/.test(file) || !existsSync(file) || !statSync(file).isFile()) return next();
|
||||
const v = currentAssetVersion();
|
||||
const text = readFileSync(file, 'utf8')
|
||||
.replace(/((?:href|src)="\/(?:css|js)\/[\w.-]+\.(?:css|js))"/g, `$1?v=${v}"`)
|
||||
.replace(/(from\s+'\.\/[\w.-]+\.js)'/g, `$1?v=${v}'`);
|
||||
res.type(extname(file));
|
||||
res.setHeader('Cache-Control', cacheControl);
|
||||
res.send(text);
|
||||
};
|
||||
}
|
||||
|
||||
// ---------- App ----------
|
||||
const app = express();
|
||||
app.disable('x-powered-by');
|
||||
@@ -189,6 +229,7 @@ app.use('/api/patches', express.json({ limit: '12mb' }));
|
||||
app.use(express.json({ limit: '1mb' }));
|
||||
|
||||
// Öffentlich: Startseite, Login, CSS/Bilder
|
||||
app.use(versioned(join(ROOT, 'public'), 'no-cache'));
|
||||
app.use(express.static(join(ROOT, 'public'), { extensions: ['html'] }));
|
||||
authRoutes(app);
|
||||
|
||||
@@ -309,6 +350,7 @@ app.delete('/api/patches/:id', (req, res) => {
|
||||
saveDb();
|
||||
res.status(204).end();
|
||||
});
|
||||
app.use(versioned(join(ROOT, 'private'), 'private, no-cache'));
|
||||
app.use(express.static(join(ROOT, 'private'), {
|
||||
extensions: ['html'],
|
||||
setHeaders: (res) => res.setHeader('Cache-Control', 'private, no-cache'),
|
||||
|
||||
Reference in new issue
Block a user