This commit is contained in:
seb
2026-09-25 07:27:37 +02:00
parent b331f8f535
commit a3db1742e7
17 changed files with 2273 additions and 371 deletions

View File

@@ -158,6 +158,55 @@ const sharedServer = {
},
};
function nginxHeadersPreviewPlugin() {
return {
name: 'nginx-headers-preview',
configurePreviewServer(server) {
server.middlewares.use((req, res, next) => {
const url = (req.url || '').split('?')[0];
// Never touch API requests (proxied to backend)
if (url.startsWith('/api')) {
return next();
}
// --- Security Headers (from deploy/nginx-dashfront.conf lines 72-76) ---
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
res.setHeader('Permissions-Policy', 'camera=(self), microphone=(), geolocation=()');
// --- Caching Rules (from deploy/nginx-dashfront.conf lines 129-166) ---
if (/^\/(sw\.js|registerSW\.js|workbox-[a-f0-9]+\.js)$/.test(url)) {
// Zero caching for Service Worker & registration scripts
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
} else if (/^\/(manifest\.webmanifest|favicon\.svg|icons\/.*)$/.test(url)) {
// 1 hour for web manifest & icons
res.setHeader('Cache-Control', 'public, max-age=3600');
res.setHeader('Vary', 'Accept-Encoding');
} else if (url.startsWith('/assets/')) {
// 1 year immutable for hashed assets
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
res.setHeader('Vary', 'Accept-Encoding');
} else if (url.endsWith('.wasm')) {
// 1 year immutable for WASM binaries
res.setHeader('Content-Type', 'application/wasm');
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
} else if (url === '/' || url === '/index.html' || !path.extname(url)) {
// HTML5 SPA Entry / Fallback: Zero caching
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
}
next();
});
},
};
}
export default defineConfig(({ command }) => ({
resolve: sharedResolve,
build: {
@@ -231,6 +280,7 @@ export default defineConfig(({ command }) => ({
},
plugins: [
react(),
nginxHeadersPreviewPlugin(),
...(command === 'build'
? [
VitePWA({