/// import { fileURLToPath } from "node:url"; import stylex from "@stylexjs/unplugin"; import react from "@vitejs/plugin-react"; import { type Plugin, defineConfig } from "vite"; /** * StyleX's Vite plugin polls its CSS store every 150ms from `configureServer` * and pushes an HMR event when it changes. It clears that timer from the close * event of `server.httpServer`. Vitest runs the dev server in middleware mode, * where `httpServer` is null, so the timer is never cleared: the run finishes, * the event loop stays awake, and vitest kills the worker after ten seconds with * "something prevents Vite server from exiting". A test needs StyleX's * transform, which is a different hook, and never needs its HMR — so drop this * one hook under vitest and keep the plugin. * * Remove this once @stylexjs/unplugin clears the timer on `buildEnd` or guards * the hook, and check that `npm test` still exits without the warning. */ function withoutDevServerPolling(plugin: Plugin | Plugin[]): Plugin[] { return (Array.isArray(plugin) ? plugin : [plugin]).map(({ configureServer: _dropped, ...rest }) => rest); } function stylexPlugin(mode: string): Plugin | Plugin[] { // StyleX resolves the `.stylex.ts` theme file itself, so it needs the `@` // alias too — `resolve.alias` below is Vite's and the plugin cannot see it. const configured = stylex.vite({ useCSSLayers: true, dev: mode === "development", runtimeInjection: false, aliases: { "@/*": [fileURLToPath(new URL("./src/*", import.meta.url))] }, }); return process.env.VITEST === undefined ? configured : withoutDevServerPolling(configured); } export default defineConfig(({ mode }) => ({ plugins: [stylexPlugin(mode), react()], resolve: { alias: { "@": fileURLToPath(new URL("./src", import.meta.url)), }, }, server: { proxy: { "/api": "http://127.0.0.1:8080", "/metrics": "http://127.0.0.1:8080", }, }, test: { environment: "jsdom", globals: true, setupFiles: ["./vitest.setup.ts"], }, }));