Ctrl K
ComunidadGuías…

frontend/vite.config.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { defineConfig, type Plugin } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
import fs from "fs";
import { createHash } from "node:crypto";
import { rnnoiseWasmPlugin } from "./scripts/rnnoise-wasm.mjs";

function manualChunks(id: string): string | undefined {
  const normalized = id.split(path.sep).join("/");

  if (normalized.endsWith("/src/data/tools.ts") || normalized.endsWith("/src/data/non-pdf-tools.ts")) {
    return "tool-catalog";
  }

  if (!normalized.includes("/node_modules/")) {
    return undefined;
  }

  if (
    normalized.includes("/node_modules/react/") ||
    normalized.includes("/node_modules/react-dom/") ||
    normalized.includes("/node_modules/react-router") ||
    normalized.includes("/node_modules/@remix-run/router/")
  ) {
    return "vendor-react";
  }

  if (
    normalized.includes("/node_modules/@radix-ui/react-tooltip/") ||
    normalized.includes("/node_modules/@radix-ui/react-dialog/") ||
    normalized.includes("/node_modules/@radix-ui/react-tabs/") ||
    normalized.includes("/node_modules/@radix-ui/react-select/") ||
    normalized.includes("/node_modules/@radix-ui/react-slot/")
  ) {
    return "vendor-radix";
  }

  if (normalized.includes("/node_modules/lucide-react/")) {
    return "vendor-icons";
  }

  return undefined;
}

/** Every deployed asset graph gets a fresh offline shell and an update notice. */
function serviceWorkerVersionPlugin(): Plugin {
  let outputDirectory = path.resolve(__dirname, "dist");
  return {
    name: "privatools-service-worker-version",
    apply: "build",
    configResolved(config) {
      outputDirectory = path.resolve(config.root, config.build.outDir);
    },
    writeBundle() {
      const workerPath = path.join(outputDirectory, "sw.js");
      const worker = fs.readFileSync(workerPath, "utf8");
      const digest = createHash("sha256")
        .update(fs.readFileSync(path.join(outputDirectory, "index.html")))
        .update(fs.readdirSync(path.join(outputDirectory, "assets")).sort().join("\n"))
        .update(fs.readFileSync(path.join(outputDirectory, "manifest.json")))
        .update(worker);
      for (const asset of [
        "icons/icon-192.png", "icons/icon-512.png", "icons/icon-maskable-512.png",
        "brand/privatools-icon-96.png", "brand/privatools-favicon.svg", "brand/privatools-icon-180.png",
        "experience/air-mist.png", "experience/air-graphite.png",
      ]) {
        digest.update(fs.readFileSync(path.join(outputDirectory, asset)));
      }
      const version = `v2.${digest.digest("hex").slice(0, 16)}`;
      if (!worker.includes('const CACHE_VERSION = "v2.0.0";')) {
        throw new Error("Service worker version marker is missing.");
      }
      fs.writeFileSync(workerPath, worker.replace('const CACHE_VERSION = "v2.0.0";', `const CACHE_VERSION = "${version}";`));
      console.log(`[pwa] offline shell ${version}`);
    },
  };
}

export default defineConfig({
  server: {
    host: "::",
    port: Number(process.env.PORT) || 8080,
    strictPort: false,
    hmr: { overlay: false },
    proxy: {
      "/api/": {
        // Override when the backend runs somewhere else, e.g.
        //   VITE_DEV_API_TARGET=http://localhost:8001 npm run dev
        target: process.env.VITE_DEV_API_TARGET || "http://localhost:8000",
        changeOrigin: true,
      },
    },
  },
  // rnnoiseWasmPlugin: Voice Noise Remover's RNNoise WebAssembly, emitted as an asset of its own (scripts/rnnoise-wasm.mjs).
  plugins: [react(), serviceWorkerVersionPlugin(), rnnoiseWasmPlugin()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
  build: {
    modulePreload: {
      resolveDependencies: (_filename, deps) =>
        deps.filter(dep => !/(^|\/)(vendor-icons|tool-catalog)-/.test(dep)),
    },
    rollupOptions: {
      output: {
        // Split large vendor libraries into separate cached chunks so
        // returning users get them from the SW/CDN cache instead of
        // re-downloading on every deploy. Vite 8/Rolldown requires the
        // function form here; the object form Rollup accepted in Vite 5 now
        // fails at build time.
        manualChunks,
      },
    },
    // Target modern browsers for smaller output
    target: "es2020",
    // The expected >600 kB JS chunks are lazy: the @huggingface/transformers
    // runtime for AI PDF tools, and gpt-tokenizer's two rank tables for the
    // AI Token Counter, which this warning names on every build
    // (scripts/check-bundle-size.mjs gives them ceilings of their own). Keep
    // the warning below 1 MB so accidental eager bundles still fail loudly.
    chunkSizeWarningLimit: 900,
  },
  esbuild: {
    // Drop dev-only console calls + debugger statements from the production
    // bundle so accidental `console.log("foo", bigObject)` left in tool UIs
    // doesn't ship to users. `console.error` / `console.warn` are kept so
    // real failures still surface in production telemetry.
    drop: ["debugger"],
    pure: ["console.log", "console.debug", "console.trace"],
  },
});