Newer
Older
bugtrail / packages / web / vite.config.ts
import { defineConfig, type Plugin } from "vite";
import vue from "@vitejs/plugin-vue";
import { viteStaticCopy } from "vite-plugin-static-copy";
import { createReadStream, existsSync, statSync } from "node:fs";
import { join, normalize } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = fileURLToPath(new URL(".", import.meta.url));

const KIT_DIR = "../../node_modules/gnexus-ui-kit/dist";

/**
 * gnexus-ui-kit's kit.css references fonts/images with absolute /assets/... URLs.
 * The kit's dist/assets must be served from the site root /assets in dev AND prod.
 */
function serveKitAssets(): Plugin {
  return {
    name: "serve-kit-assets",
    configureServer(server) {
      server.middlewares.use((req, res, next) => {
        const url = (req.url || "").split("?")[0];
        if (!url.startsWith("/assets/")) return next();
        const rel = normalize(decodeURIComponent(url.replace(/^\//, "")));
        const file = join(__dirname, KIT_DIR, rel);
        if (!file.startsWith(join(__dirname, KIT_DIR)) || !existsSync(file) || !statSync(file).isFile()) return next();
        const ext = file.split(".").pop();
        const types: Record<string, string> = {
          ttf: "font/ttf", woff: "font/woff", woff2: "font/woff2", css: "text/css",
          svg: "image/svg+xml", png: "image/png", jpg: "image/jpeg", ico: "image/x-icon",
        };
        res.setHeader("Content-Type", types[ext ?? ""] ?? "application/octet-stream");
        createReadStream(file).pipe(res);
      });
    },
  };
}

export default defineConfig({
  plugins: [
    vue(),
    serveKitAssets(),
    viteStaticCopy({
      targets: [{ src: `${KIT_DIR}/assets/*`, dest: "assets" }],
    }),
  ],
  server: {
    port: 5173,
    proxy: {
      "/api": { target: "http://localhost:8001", changeOrigin: true },
    },
  },
  build: {
    outDir: "dist",
    sourcemap: false,
  },
});