demo/vite.config.ts

import { fileURLToPath } from "node:url";
import { transformAsync } from "@babel/core";
// @ts-expect-error — no types ship with @babel/preset-react
import presetReact from "@babel/preset-react";
import { defineConfig, type Plugin } from "vite";
import solid from "vite-plugin-solid";

const demoRoot = fileURLToPath(new URL("./", import.meta.url));
const repoRoot = fileURLToPath(new URL("../", import.meta.url));

/** The Base UI (React) "ground truth" half of the side-by-side gallery. */
const REACT_DEMOS = /\/demo\/src\/react\//;

/**
 * React-only JSX transform for the side-by-side demo gallery.
 *
 * Files under `demo/src/react/**` are the Base UI ground-truth demos; they
 * compile with `@babel/preset-react` (automatic runtime). Babel only lowers
 * JSX; Vite's own esbuild pass strips the remaining TypeScript afterwards.
 *
 * Everything else (the Quoin library + `demo/src/solid/**`) is handled by
 * `vite-plugin-solid` below, configured with the SAME `babel-preset-solid`
 * options the library's Bun build uses (`scripts/solid-plugin.ts`):
 * `{ moduleName: "@solidjs/web", generate: "dom", hydratable: false }`.
 */
function reactJsxBabel(): Plugin {
	const JSX = /\.[jt]sx(?:$|\?)/;
	return {
		name: "react-jsx-babel",
		enforce: "pre",
		async transform(code, id) {
			const file = id.split("?")[0] ?? id;
			if (!JSX.test(id) || !REACT_DEMOS.test(file)) return null;

			const result = await transformAsync(code, {
				filename: file,
				configFile: false,
				babelrc: false,
				sourceMaps: true,
				parserOpts: { plugins: ["typescript", "jsx"] },
				presets: [[presetReact, { runtime: "automatic" }]],
			});

			if (!result?.code) return null;
			return { code: result.code, map: result.map };
		},
	};
}

export default defineConfig({
	root: demoRoot,
	plugins: [
		reactJsxBabel(),
		solid({
			// The React demos are compiled by `reactJsxBabel` above.
			exclude: REACT_DEMOS,
			solid: {
				moduleName: "@solidjs/web",
				generate: "dom",
				hydratable: false,
			},
		}),
	],
	resolve: {
		conditions: ["development", "browser"],
		// One copy of each runtime — duplicates break reactivity / React context.
		dedupe: [
			"solid-js",
			"@solidjs/web",
			"@solidjs/signals",
			"react",
			"react-dom",
		],
	},
	optimizeDeps: {
		include: [
			"solid-js",
			"@solidjs/web",
			"@solidjs/signals",
			"react",
			"react-dom",
			"react-dom/client",
			"react/jsx-runtime",
		],
	},
	server: {
		// Demos import component source from `../src`, outside the Vite root.
		fs: { allow: [repoRoot] },
	},
});