import * as fs from "node:fs"; import * as path from "node:path"; import react from "@vitejs/plugin-react"; import { defineConfig, type Plugin } from "vite"; /** * Serve /wasm/*.gz as opaque bytes WITHOUT `Content-Encoding: gzip`. * * Vite's static (sirv) sets `Content-Encoding: gzip` for `.gz` files. The * browser then transparently decompresses the response, so the harness's * `fetch('images.tar.gz')` receives the DECOMPRESSED tar — and KiCad's gunzip * of it fails with "Can't read from inflate stream: incorrect header check". * We must hand the browser the raw gzip bytes, so we serve them ourselves with * no Content-Encoding. Runs before the public-dir middleware. */ function serveWasmGzRaw(): Plugin { const publicDir = path.resolve(__dirname, "public"); return { name: "serve-wasm-gz-raw", configureServer(server) { server.middlewares.use((req, res, next) => { const url = req.url?.split("?")[0] ?? ""; if (!/^\/wasm\/.+\.gz$/.test(url)) return next(); const filePath = path.join(publicDir, decodeURIComponent(url)); fs.stat(filePath, (err, st) => { if (err || !st.isFile()) return next(); res.setHeader("Content-Type", "application/octet-stream"); res.setHeader("Content-Length", st.size); // Intentionally NO Content-Encoding so fetch() yields raw gzip bytes. fs.createReadStream(filePath).pipe(res); }); }); }, }; } export default defineConfig({ plugins: [serveWasmGzRaw(), react()], resolve: { alias: { "@": path.resolve(__dirname, "./src"), }, }, server: { port: 3048, // KiCad WASM is cross-origin-isolated (COOP/COEP); same-origin /wasm assets // load fine. Keep these so SharedArrayBuffer/threads are available. headers: { "Cross-Origin-Opener-Policy": "same-origin", "Cross-Origin-Embedder-Policy": "require-corp", }, }, preview: { headers: { "Cross-Origin-Opener-Policy": "same-origin", "Cross-Origin-Embedder-Policy": "require-corp", }, }, });