Files
gitmost/apps/client/vite.config.ts
agent_coder babc42c2ff fix(#346 review F1-F4): no 206-compress + Vary + precompress VAD + cache test
- F1 [HIGH — data corruption]: @fastify/compress was compressing 206/Range
  attachment responses while Content-Range still described the RAW offsets, so a
  resuming client (curl -C -, download managers) appended encoded bytes as raw →
  corrupted file. sendFileResponse now sets the request header `x-no-compression`
  (the documented @fastify/compress opt-out — its onSend skips when the request
  carries it; the reviewer's `Content-Encoding: identity` does NOT work because
  compress explicitly excludes `identity` and overwrites it). This opts the whole
  download route (both 200 full-file and 206 range) out of on-the-fly compression
  — correct, since attachment bytes are final and mostly binary.
- F2: static responses now emit `Vary: Accept-Encoding` (the preCompressed
  content-negotiated /assets/* were `immutable` without Vary → shared-cache could
  serve a brotli variant to an identity/gzip-only client).
- F3: vite compression `include` extended to .wasm/.onnx so the VAD binaries
  (~26MB .wasm, ~2.3MB .onnx under public/vad) are precompressed at build (.br
  emitted) instead of runtime-brotli'd on every request. (include REPLACES the
  plugin default, so the default js/css/json/html set is re-listed.)
- F4: extracted the cache classification into a pure `resolveStaticAssetHeaders`
  + static.module.spec.ts (3 tests: /assets/* immutable+Vary, index.html
  no-store, non-hashed not-immutable).

Gate: server tsc 0 (deps present), static.module.spec 3/3, client build emits
.wasm.br/.onnx.br, frozen install 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 04:13:20 +03:00

115 lines
3.2 KiB
TypeScript

import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";
import { compression } from "vite-plugin-compression2";
import * as path from "path";
import { execSync } from "node:child_process";
const envPath = path.resolve(process.cwd(), "..", "..");
// Resolve the version string shown in the UI.
// Priority: explicit APP_VERSION env (injected by Docker/CI, where .git is absent),
// then `git describe` for local builds, then the package.json version as a fallback.
function resolveAppVersion(cwd: string): string {
const fromEnv = process.env.APP_VERSION?.trim();
if (fromEnv) return fromEnv;
try {
return execSync("git describe --tags --always", {
cwd,
stdio: ["ignore", "pipe", "ignore"],
})
.toString()
.trim();
} catch {
return `v${process.env.npm_package_version ?? "0.0.0"}`;
}
}
export default defineConfig(({ mode }) => {
const {
APP_URL,
FILE_UPLOAD_SIZE_LIMIT,
FILE_IMPORT_SIZE_LIMIT,
DRAWIO_URL,
CLOUD,
SUBDOMAIN_HOST,
COLLAB_URL,
BILLING_TRIAL_DAYS,
POSTHOG_HOST,
POSTHOG_KEY,
} = loadEnv(mode, envPath, "");
return {
define: {
"process.env": {
APP_URL,
FILE_UPLOAD_SIZE_LIMIT,
FILE_IMPORT_SIZE_LIMIT,
DRAWIO_URL,
CLOUD,
SUBDOMAIN_HOST,
COLLAB_URL,
BILLING_TRIAL_DAYS,
POSTHOG_HOST,
POSTHOG_KEY,
},
APP_VERSION: JSON.stringify(resolveAppVersion(envPath)),
},
plugins: [
react(),
// Emit .br and .gz next to every built asset so the server can serve the
// precompressed copy (see @fastify/static preCompressed in static.module.ts).
compression({
algorithms: ["brotliCompress", "gzip"],
// vite-plugin-compression2's default `include` only covers text-ish
// bundle output (js/mjs/json/css/html/svg/…). Extend it with the large
// VAD binaries copied from public/vad (.wasm ~26MB, .onnx ~2.3MB) so
// they are brotli/gzip'd once at build time and served via
// @fastify/static preCompressed — otherwise @fastify/compress would
// re-brotli them on EVERY request. The default types are repeated here
// because setting `include` replaces (does not extend) the default.
include: /\.(html|xml|css|json|js|mjs|svg|yaml|yml|toml|wasm|onnx)$/,
// index.html is rewritten at server boot (window.CONFIG injection); a
// precompressed copy would go stale — NEVER precompress it.
exclude: [/index\.html$/],
}),
],
build: {
rolldownOptions: {
output: {
advancedChunks: {
groups: [
{
name: "vendor-mantine",
test: /[\\/]node_modules[\\/]@mantine[\\/]/,
},
],
},
},
},
},
resolve: {
alias: {
"@": "/src",
},
},
server: {
proxy: {
"/api": {
target: APP_URL,
changeOrigin: false,
},
"/socket.io": {
target: APP_URL,
ws: true,
rewriteWsOrigin: true,
},
"/collab": {
target: APP_URL,
ws: true,
rewriteWsOrigin: true,
},
},
},
};
});