Files
visiome.neuroinf.jp/vite.config.ts
T
orrisroot 0271796534 fix: make the browser revalidate the site data
sirv sent no Cache-Control for static-contents, only an ETag, so the
browser was free to apply heuristic caching and answer from a stale
copy without revalidating. A re-dump would then go unnoticed, and two
sites served from the same localhost port answered with each other's
JSON.

maxAge 0 sends `public, max-age=0, must-revalidate`; a matching ETag
still yields a 304, so nothing extra is transferred.
2026-09-11 21:23:53 +09:00

63 lines
2.4 KiB
TypeScript

import fs from 'node:fs';
import path from 'node:path';
import react from '@vitejs/plugin-react';
import sirv from 'sirv';
import type { Connect, Plugin, ResolvedConfig } from 'vite';
import { defineConfig } from 'vite';
/**
* `static-contents/` holds the dumped site data (`modules/`, `rss.xml`).
* It sits next to the repository and is served from the site root next to
* `public/`, but it is deliberately kept out of the bundle: it runs to
* gigabytes of frozen data that the web server maps in directly. The dev and
* preview servers mount it so that both behave like production.
*/
const staticContents = (): Plugin => {
let dir: string;
const mount = (middlewares: { use: (fn: Connect.NextHandleFunction) => void }, dev: boolean) => {
if (fs.existsSync(dir)) {
// maxAge 0 makes sirv send `Cache-Control: public, max-age=0`, so the
// browser revalidates against the ETag instead of falling back to
// heuristic caching. Without it a re-dump, or another site served
// from the same localhost port, is answered from a stale cache.
middlewares.use(sirv(dir, { dev, etag: true, maxAge: 0 }));
}
};
return {
name: 'visiome:static-contents',
configResolved(config: ResolvedConfig) {
dir = path.resolve(config.root, '../static-contents');
},
configureServer(server) {
mount(server.middlewares, true);
},
configurePreviewServer(server) {
mount(server.middlewares, false);
},
};
};
// https://vite.dev/config/
export default defineConfig({
plugins: [react(), staticContents()],
optimizeDeps: { exclude: ['fs'] },
build: {
sourcemap: true,
rolldownOptions: {
external: ['fs'],
output: {
// react and react-dom are over 200 kB together, which would
// push a single dependency chunk past the 500 kB warning
// threshold. They also change far less often than the rest,
// so split them off and let the two cache independently.
codeSplitting: {
groups: [
{ name: 'vendor-react', test: /node_modules\/(react|react-dom|scheduler)\// },
{ name: 'vendor-misc', test: /node_modules\// },
],
},
},
},
},
});