Files
ihasmail-inbuxa/web/vite.config.ts
T
jcoffey-dev 53ccaad468 Move the build to vite 8, and chunk the way rolldown wants
@vitejs/plugin-react 6 peers on vite ^8 and nothing lower, so the build
had to move before the plugin could. vite 8 bundles with rolldown rather
than rollup, which is most of what is here.

The object form of `manualChunks` -- a chunk name against the list of
packages in it -- is gone; rolldown takes groups tested against module
paths instead. Same two chunks come out, `vendor` and `icons`, with the
same contents; `icons` is tried first because the first matching group
wins. `rollupOptions` is now a deprecated alias, so it is spelled
`rolldownOptions`.

The lockfile is regenerated rather than patched. vitest depends on vite
itself, and an incremental install was happy to leave 6.4.3 hoisted for
vitest while web built against 8.3.0 -- two majors in one tree, which is
not a state to ship. A clean install collapses to one.

vite 8 wants Node ^20.19 || >=22.12, above the >=20.10 the README and
engines promised, so both say 20.19 now. CI and the image are on 22 and
were never affected.

Rolldown reports two modules that are imported both statically and
dynamically, so the dynamic import cannot split them out. That is true
of the source either way -- store/sieve.ts has three static importers
and one dynamic -- and is left alone here.
2026-09-10 08:03:40 -07:00

73 lines
2.6 KiB
TypeScript

import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
import { fileURLToPath, URL } from "node:url";
import { resolveVersion } from "../scripts/version.mjs";
import { baseUrlOf } from "../scripts/basePath.mjs";
// Resolved here, at build time: the browser has no git to ask, and neither does
// the Docker build, which is handed the answer as IHASMAIL_VERSION instead.
const version = resolveVersion();
/*
* Where the app is mounted. Unlike everything else ihasmail is told, this one
* cannot wait until the process starts: the hashed asset URLs are written into
* index.html when the bundle is built, so a build that does not know its prefix
* emits `/assets/...` and the shell 404s under `/mail/`. So `BASE_PATH` is read
* at build time here as well as at run time in the server, and the Dockerfile
* carries one value into both.
*
* Vite wants the directory form with the trailing slash, and hands it back to
* the app as `import.meta.env.BASE_URL` -- which is where `lib/basePath.ts`
* gets it, so the browser never has to be told separately.
*/
const base = baseUrlOf(process.env.BASE_PATH);
export default defineConfig({
base,
plugins: [react()],
define: { __IHASMAIL_VERSION__: JSON.stringify(version) },
resolve: {
alias: { "@": fileURLToPath(new URL("./src", import.meta.url)) },
},
server: {
port: 5173,
proxy: {
// Under a prefix the dev server serves the app from `base`, so the app's
// API calls arrive here prefixed too. Forwarded whole, prefix included:
// the dev server behind this reads the same BASE_PATH and expects it.
[`${base}api`]: {
target: "http://127.0.0.1:8080",
changeOrigin: false,
},
},
},
build: {
target: "es2022",
sourcemap: false,
rolldownOptions: {
output: {
/*
* Rolldown, which vite 8 bundles with, dropped the object form of
* `manualChunks` -- naming a chunk and listing the packages in it --
* and takes groups matched against module paths instead. Same two
* chunks out the other end; `icons` is listed first because groups are
* tried in order and the first match wins.
*/
codeSplitting: {
groups: [
{ name: "icons", test: /node_modules[\\/]lucide-react[\\/]/ },
{
name: "vendor",
test: /node_modules[\\/](wouter|zustand|dompurify|@tanstack[\\/]react-virtual)[\\/]/,
},
],
},
},
},
},
test: {
environment: "jsdom",
include: ["src/**/*.test.ts", "src/**/*.test.tsx"],
},
});