vite.config.ts
Rama master · réplica de lectura del repositorio original.
import { execSync } from 'node:child_process';
import { defineConfig } from 'vite';
// Short source revision, surfaced in the UI so "did this deploy reach me?"
// is answerable at a glance (info panel build row).
const buildId = (() => {
// CI and constrained builders can supply the revision even when spawning Git is unavailable.
const supplied = process.env.WISH_BUILD_ID?.trim();
if (supplied) return supplied.slice(0, 12);
try { return execSync('git rev-parse HEAD').toString().trim().slice(0, 12); }
catch { return 'dev'; }
})();
// Unique for every build, including two deployments built from the same commit.
const webBuildId = `${buildId}-${Date.now().toString(36)}`;
import vue from '@vitejs/plugin-vue';
import pxtorem from 'postcss-pxtorem';
import { VitePWA } from 'vite-plugin-pwa';
import { pdfAssets } from './tools/pdf-assets.ts';
export default defineConfig({
cacheDir: '.cache/vite',
// Adjust only the CJK faces, including Fontsource's generated shards.
// Latin, monospace and math retain their own metrics.
css: { postcss: { plugins: [{
postcssPlugin: 'wish-cjk-metrics',
AtRule: {
'font-face': (rule) => {
rule.walkDecls('font-family', (family) => {
const name = family.value.replace(/["']/g, '');
const scale = name === 'Sarasa Gothic SC' ? '95%'
: name === 'Noto Serif SC Variable' ? '96%' : undefined;
if (scale) rule.append({ prop: 'size-adjust', value: scale });
});
},
},
},
// Font sizes are written in px and served in rem, so the text size setting scales them all.
pxtorem({ rootValue: 16, propList: ['font', 'font-size', 'line-height', 'letter-spacing', '--message-size'], minPixelValue: 2 }),
] } },
plugins: [
pdfAssets(),
// Kept out of Workbox's precache (which only includes HTML/CSS/JS/images).
// Fetching this file therefore asks the live server even from an old tab.
{ name: 'wish-build-info',
configureServer(server) {
server.middlewares.use('/build-info.json', (_req, res) => {
res.setHeader('Content-Type', 'application/json');
res.setHeader('Cache-Control', 'no-store');
res.end(JSON.stringify({ id: webBuildId }));
});
},
generateBundle() { this.emitFile({ type: 'asset', fileName: 'build-info.json', source: JSON.stringify({ id: webBuildId }) }); },
},
vue(),
VitePWA({
registerType: 'prompt',
injectRegister: false,
manifest: false,
includeAssets: ['manifest.webmanifest', 'app-icons/*.png'],
workbox: {
clientsClaim: true,
globPatterns: ['**/*.{js,css,html,png,svg,webmanifest}'],
globIgnores: ['pdfjs/**'],
// Requests the auth proxy in front of the app must answer itself: the service worker's
// shell would otherwise stand in for a login page (and for a logout that redirects).
navigateFallbackDenylist: [/^\/api(?:\/|$)/, /^\/healthz$/, /^\/login(?:\/|\?|$)/, /^\/logout(?:\/|\?|$)/],
cleanupOutdatedCaches: true,
// Fontsource splits CJK by unicode range. Cache only requested shards;
// precaching the complete font families would download unused glyphs.
runtimeCaching: [{
urlPattern: /\/assets\/(?:noto-|sarasa-|maple-|STIXTwoMath-|montserrat-|bitter-).*\.woff2$/,
handler: 'CacheFirst',
options: { cacheName: 'wish-fonts', expiration: { maxEntries: 180, maxAgeSeconds: 31536000 } },
}],
},
}),
],
define: { __BUILD_ID__: JSON.stringify(buildId), __WEB_BUILD_ID__: JSON.stringify(webBuildId) },
build: { target: 'es2022', manifest: true },
server: {
proxy: {
'/api': { target: process.env.WISH_UPSTREAM || 'http://127.0.0.1:9780', headers: process.env.WISH_HTTP_TOKEN ? { Authorization: `Bearer ${process.env.WISH_HTTP_TOKEN}` } : {} },
},
},
});