import { fileURLToPath, URL } from 'node:url' import { createRequire } from 'node:module' import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' const require = createRequire(import.meta.url) const { isSharedExternal, isAdminLangExternal, adminLangExternalPath, isCoreExternal, coreExternalPath } = require('./scripts/shared-external.cjs') const { stripElementPlusStylePlugin } = require('./scripts/vite-plugin-strip-element-plus-style.cjs') const addonKey = process.env.ADDON_KEY || '' if (!addonKey) { throw new Error('ADDON_KEY is required for addon build') } const entry = fileURLToPath(new URL(`./.build/addons/${addonKey}/entry.ts`, import.meta.url)) const elementPlusResolver = ElementPlusResolver({ importStyle: false }) /** 单插件生产构建 */ export default defineConfig({ base: '', publicDir: false, define: { 'process.env.NODE_ENV': JSON.stringify('production'), __VUE_OPTIONS_API__: true, __VUE_PROD_DEVTOOLS__: false, __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false, // 显式注入 VITE_* 环境变量:lib 构建模式下 import.meta.env 替换可能不完整 'import.meta.env.VITE_APP_BASE_URL': JSON.stringify('/adminapi/'), 'import.meta.env.VITE_IMG_DOMAIN': JSON.stringify(''), 'import.meta.env.VITE_REQUEST_HEADER_TOKEN_KEY': JSON.stringify('token'), 'import.meta.env.VITE_REQUEST_HEADER_SITEID_KEY': JSON.stringify('site-id'), 'import.meta.env.VITE_DETAULT_TITLE': JSON.stringify('') }, css: { // 插件独立打包时,让 Tailwind 扫描插件源码并生成用到的工具类, // 随 style.css 一起运行时注入,避免主后台未生成插件特有的 Tailwind 类导致样式丢失。 postcss: { plugins: [ require('tailwindcss')(require('./tailwind.addon.config.cjs')), require('autoprefixer')() ] } }, plugins: [ // 修复:addon 中 import X from '@/utils/storage' / '@/utils/config' 的 default import // 会被错误地 external 到 core-shared.js 的 default 导出(即 request 实例)。 // core-shared 的 export * 不转发 default,因此需要改写为命名导入。 { name: 'fix-addon-storage-config-default-import', enforce: 'pre', transform(code, id) { // 只在 addon 构建中使用(vite.config.addon.ts 专用),无需 id 过滤 // import xxx from '@/utils/storage' → import { storage as xxx } from '@/utils/storage' const orig = code code = code.replace( /import\s+(\w+)\s+from\s+['"]@\/utils\/storage['"]/g, "import { storage as $1 } from '@/utils/storage'" ) // import xxx from '@/utils/config' → import { config as xxx } from '@/utils/config' code = code.replace( /import\s+(\w+)\s+from\s+['"]@\/utils\/config['"]/g, "import { config as $1 } from '@/utils/config'" ) // import xxx from '@/utils/test' → import { test as xxx } from '@/utils/test' code = code.replace( /import\s+(\w+)\s+from\s+['"]@\/utils\/test['"]/g, "import { test as $1 } from '@/utils/test'" ) // 处理导出同名冲突:import { X } from '@/app/api/mod' / '@/utils/mod' // 优先 export-conflicts.json,兼容旧版 api-conflicts.json let conflicts = {} const sources = [ fileURLToPath(new URL('./.build/export-conflicts.json', import.meta.url)), fileURLToPath(new URL('./.build/api-conflicts.json', import.meta.url)) ] for (const p of sources) { try { conflicts = { ...conflicts, ...require(p) } } catch (_) {} } if (Object.keys(conflicts).length) { code = code.replace( /import\s+\{([^}]+)\}\s+from\s+['"]@\/(?:app\/api|utils)\/(\w+)['"]/g, (match: string, names: string, mod: string) => { const remapped = names.split(',').map(n => { const trimmed = n.trim() const [name, alias] = trimmed.includes(' as ') ? trimmed.split(' as ').map(s => s.trim()) : [trimmed, trimmed] const key = mod + ':' + name if (conflicts[key]) return conflicts[key] + ' as ' + alias return trimmed }) const ns = match.includes('@/app/api') ? '@/app/api' : '@/utils' return 'import { ' + remapped.join(', ') + ' } from \'' + ns + '/' + mod + '\'' } ) } // 处理 export { default as ... } from '@/utils/storage|config|test' code = code.replace( /export\s+\{\s*default\s+as\s+(\w+)\s*\}\s+from\s+['"]@\/utils\/(storage|config|test)['"]/g, "export { $2 as $1 } from '@/utils/$2'" ) if (code !== orig) { return { code, map: null } } } }, stripElementPlusStylePlugin(), vue(), AutoImport({ resolvers: [elementPlusResolver] }), Components({ resolvers: [elementPlusResolver] }), // 注入 CSS:lib 模式 CSS 统一提取到 style.css,运行时注入为