import { defineConfig } from 'vite'; import { resolve } from 'path'; import dts from 'vite-plugin-dts'; import react from '@vitejs/plugin-react'; /** * 自定义插件:将 CSS 转换为自执行的样式注入代码 * Custom plugin: Convert CSS to self-executing style injection code * * 当用户写 `import './styles.css'` 时,这个插件会: * 1. 在构建时将 CSS 内容转换为 JS 代码 * 2. JS 代码在模块导入时自动执行,将样式注入到 DOM * 3. 使用唯一 ID 防止重复注入 * * When user writes `import './styles.css'`, this plugin will: * 1. Convert CSS content to JS code during build * 2. JS code auto-executes when module is imported, injecting styles to DOM * 3. Uses unique ID to prevent duplicate injection */ function injectCSSPlugin(): any { const cssIdMap = new Map(); let cssCounter = 0; return { name: 'inject-css-plugin', enforce: 'post' as const, generateBundle(_options: any, bundle: any) { const bundleKeys = Object.keys(bundle); // 找到所有 CSS 文件 const cssFiles = bundleKeys.filter(key => key.endsWith('.css')); for (const cssFile of cssFiles) { const cssChunk = bundle[cssFile]; if (!cssChunk || !cssChunk.source) continue; const cssContent = cssChunk.source; const styleId = `esengine-tilemap-style-${cssCounter++}`; cssIdMap.set(cssFile, styleId); // 生成样式注入代码 const injectCode = `(function(){if(typeof document!=='undefined'){var s=document.createElement('style');s.id='${styleId}';if(!document.getElementById(s.id)){s.textContent=${JSON.stringify(cssContent)};document.head.appendChild(s);}}})();`; // 找到引用此 CSS 的 JS chunk 并注入代码 for (const jsKey of bundleKeys) { if (!jsKey.endsWith('.js')) continue; const jsChunk = bundle[jsKey]; if (!jsChunk || jsChunk.type !== 'chunk' || !jsChunk.code) continue; // 检查是否引用了这个 CSS(通过检查是否有相关的 import) // 对于 vite 生成的代码,CSS 导入会被转换,所以我们直接注入到 editor/index.js if (jsKey === 'editor/index.js' || jsKey.match(/^index-[^/]+\.js$/)) { jsChunk.code = injectCode + '\n' + jsChunk.code; } } // 删除独立的 CSS 文件 delete bundle[cssFile]; } } }; } export default defineConfig({ plugins: [ react(), dts({ include: ['src'], outDir: 'dist', rollupTypes: false }), injectCSSPlugin() ], esbuild: { jsx: 'automatic', }, build: { lib: { entry: { index: resolve(__dirname, 'src/index.ts'), runtime: resolve(__dirname, 'src/runtime.ts'), 'editor/index': resolve(__dirname, 'src/editor/index.ts') }, formats: ['es'], fileName: (format, entryName) => `${entryName}.js` }, rollupOptions: { external: [ '@esengine/ecs-framework', '@esengine/ecs-components', '@esengine/ecs-engine-bindgen', '@esengine/asset-system', '@esengine/editor-core', 'react', 'react/jsx-runtime', 'lucide-react', 'zustand', /^@esengine\//, /^@tauri-apps\// ], output: { exports: 'named', preserveModules: false } }, target: 'es2020', minify: false, sourcemap: true } });