/** * Standard Microfrontend Vite Configuration Factory * * @description Creates a production-ready Vite config for microfrontends * @version Vite 8.0.0-beta.8+ * * Features: * - Library mode with ES modules output * - preserveModules for optimal tree-shaking * - External dependencies (React, Apollo, etc.) provided by host * - Hot reload in development * - Contextual @/ alias resolution * * @example * ```ts * // vite.config.ts * import { createMicrofrontendConfig } from '@burdenoff/fe-libs/vite'; * * export default createMicrofrontendConfig({ * name: 'tags', * port: 5114, * }); * ``` */ import { defineConfig, type UserConfig, type Plugin } from 'vite'; import react from '@vitejs/plugin-react'; import dts from 'vite-plugin-dts'; import { resolve, dirname } from 'path'; import { fileURLToPath } from 'url'; import { type MicrofrontendConfig, STANDARD_MFE_EXTERNALS, STANDARD_WATCH_IGNORE, MFE_PORT_MAP, } from './types'; import { createContextualAliasPlugin } from './plugins'; /** * Creates a standardized Vite configuration for microfrontends. * * @param config - Microfrontend configuration options * @param configPath - The path to the vite.config.ts file (use import.meta.url) * @returns Vite configuration object */ export function createMicrofrontendConfig( config: MicrofrontendConfig, configPath: string ): UserConfig { // Resolve __dirname from the config file path const __dirname = typeof configPath === 'string' && configPath.startsWith('file://') ? dirname(fileURLToPath(configPath)) : configPath; const { name, port = MFE_PORT_MAP[name] || 5100, entry = `${name}/index.ts`, feLibsPath = '../../fe-libs/src', additionalExternals = [], additionalAliases = {}, additionalPlugins = [], generateDts = false, } = config; const resolvedFeLibsPath = resolve(__dirname, feLibsPath); const srcPath = resolve(__dirname, './src'); // Build external array including regex patterns const externals: (string | RegExp)[] = [ ...STANDARD_MFE_EXTERNALS.filter((ext): ext is string => typeof ext === 'string'), ...additionalExternals, // Include regex patterns /^@burdenoff\/fe-libs\/.*/, ]; const plugins: Plugin[] = [ createContextualAliasPlugin({ feLibsPath: resolvedFeLibsPath, srcPath, }), react(), ...(generateDts ? [dts({ insertTypesEntry: true })] : []), ...additionalPlugins, ]; return defineConfig({ plugins, server: { port, strictPort: true, headers: { // Required for OAuth popup flows and SharedArrayBuffer 'Cross-Origin-Opener-Policy': 'same-origin-allow-popups', 'Cross-Origin-Embedder-Policy': 'unsafe-none', }, watch: { ignored: [...STANDARD_WATCH_IGNORE], }, }, build: { // Library mode configuration lib: { entry: { [name]: resolve(__dirname, `src/${entry}`), }, formats: ['es'], }, // Rolldown options (Vite 8 uses Rolldown instead of Rollup) rolldownOptions: { external: externals, output: { // Preserve module structure for optimal tree-shaking preserveModules: true, preserveModulesRoot: 'src', // Consistent file naming entryFileNames: '[name].js', chunkFileNames: 'chunks/[name].js', }, }, // Enable source maps for debugging sourcemap: true, // Don't minify library builds (app shell will minify) minify: false, // Don't empty outDir on rebuild (for watch mode) emptyOutDir: true, }, resolve: { alias: { '@burdenoff/fe-libs': resolvedFeLibsPath, ...additionalAliases, }, // Ensure consistent dependency resolution dedupe: ['react', 'react-dom', 'react-router', '@apollo/client', 'graphql', 'zustand'], }, // Vite 8 uses Oxc for transforms instead of esbuild oxc: { jsx: { runtime: 'automatic', }, }, // Optimize dependencies for faster dev startup optimizeDeps: { include: [ 'react', 'react-dom', 'react-router', '@apollo/client', 'graphql', 'lucide-react', 'zustand', ], }, }) as UserConfig; } export default createMicrofrontendConfig;