import { defineConfig } from 'vite'; import path from 'path'; import fs from 'fs'; import tailwindcss from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; // ── Monorepo dev aliases (auto-detected) ──────────────────────────────────── // When this vite.config lives inside the xertica-ui monorepo (i.e. the // `components/` directory exists one level up), we alias every `xertica-ui/*` // subpath directly to the TypeScript source so Vite HMR picks up changes // without a full `npm run build` in the library root. // // When this file is copied to a project scaffolded by the CLI, `../components` // does NOT exist and the aliases are simply skipped — the project resolves // `xertica-ui` from node_modules as normal. // ──────────────────────────────────────────────────────────────────────────── const LIB_ROOT = path.resolve(__dirname, '..'); const isMonorepo = fs.existsSync(path.join(LIB_ROOT, 'components', 'index.ts')); const libAliases = isMonorepo ? [ { find: 'xertica-ui/ui', replacement: path.join(LIB_ROOT, 'components/ui/index.ts') }, { find: 'xertica-ui/blocks', replacement: path.join(LIB_ROOT, 'components/blocks/index.ts') }, { find: 'xertica-ui/assistant', replacement: path.join(LIB_ROOT, 'components/assistant/index.ts'), }, { find: 'xertica-ui/layout', replacement: path.join(LIB_ROOT, 'components/layout/index.ts') }, { find: 'xertica-ui/brand', replacement: path.join(LIB_ROOT, 'components/brand/index.ts') }, { find: 'xertica-ui/media', replacement: path.join(LIB_ROOT, 'components/media/index.ts') }, { find: 'xertica-ui/hooks', replacement: path.join(LIB_ROOT, 'components/hooks/index.ts') }, { find: 'xertica-ui/pages', replacement: path.join(LIB_ROOT, 'components/pages/index.ts') }, { find: 'xertica-ui/style.css', replacement: path.join(LIB_ROOT, 'styles/globals.css') }, // Bare `xertica-ui` must come AFTER subpaths (most-specific first). { find: 'xertica-ui', replacement: path.join(LIB_ROOT, 'components/index.ts') }, ] : []; // ── Monorepo-only Tailwind @source shim ───────────────────────────────────── // Tailwind's content scanner walks down from the project root and never // reaches `LIB_ROOT/components` — a sibling of `templates/`, not a // descendant — even though the aliases above resolve `xertica-ui/*` imports // there. Without this, any Tailwind class used only inside library source // (and not duplicated elsewhere under templates/src) never gets generated in // this dev server. Only active in monorepo mode; scaffolded projects never // satisfy `isMonorepo`, so this plugin becomes a no-op and they keep relying // solely on the `@source` line already inside src/styles/index.css (which // targets node_modules/xertica-ui/components). const monorepoTailwindSourcePlugin = isMonorepo ? { name: 'xertica-monorepo-tailwind-source', enforce: 'pre' as const, transform(code: string, id: string) { if (id.replace(/\\/g, '/').endsWith('src/styles/index.css')) { const componentsPath = path.join(LIB_ROOT, 'components').replace(/\\/g, '/'); return `${code}\n@source '${componentsPath}';\n`; } }, } : null; export default defineConfig({ plugins: [ // The React and Tailwind plugins are both required for Make, even if // Tailwind is not being actively used — do not remove them. react(), monorepoTailwindSourcePlugin, tailwindcss(), ], resolve: { alias: [ ...libAliases, // Alias @ to the src directory { find: '@', replacement: path.resolve(__dirname, './src') }, ], }, // File types to support raw imports. Never add .css, .tsx, or .ts files to this. assetsInclude: ['**/*.svg', '**/*.csv'], // Dev-only: forwards to server/fdm-proxy.mjs (run separately via `npm run // server`) so the frontend can call same-origin `/api/...` instead of // talking to FDM directly (FDM sends no CORS headers). server: { proxy: { '/api': 'http://localhost:8787', }, }, });