Vite/Rollup构建组件库时导出名称被修改为单字符如何配置解决
Vite打包组件库导出名称被篡改问题修复
问题现象
使用Vite打包自研Vue组件库时,构建产物中导出的变量名称被压缩替换为单字符(如g),无法保留源码中的原始导出名,导致外部引用时无法匹配对应导出。
现有配置与复现代码
vite.config.js 配置
import { defineConfig } from "vite"; import path from "path"; import { createVuePlugin } from "vite-plugin-vue2"; import pkg from "./package.json"; const inspector = require("inspector"); inspector.open("9292", "127.0.0.1"); const extensions = [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue"]; export default (/** if you want to use mode : { mode }*/) => defineConfig({ mode: "production", base: "./", plugins: [createVuePlugin()], resolve: { extensions, alias: [ { find: `@gb/utils`, replacement: path.resolve(__dirname, "../../packages/utils/src"), }, ], }, css: { modules: { scopeBehaviour: "global", }, preprocessorOptions: { less: { javascriptEnabled: true, charset: false, }, scss: { charset: false, }, }, }, build: { lib: { entry: path.resolve(__dirname, "src/index.js"), name: "index", formats: ["es"], fileName: () => `index.js`, }, cssCodeSplit: true, outDir: "es", assetsDir: "style", watch: {}, minify: "minify", rollupOptions: { output: { // preserveModules: true, // preserveModulesRoot: "src", // assetFileNames: ({ name }) => { // const { ext, dir, base } = path.parse(name); // console.log(ext, dir, base); // if (ext !== ".css") return "[name].[ext]"; // return path.join(dir, "style", 'style.css'); // }, chunkFileNames: (chunkInfo) => { // console.log(chunkInfo); return "[name].js"; }, manualChunks: (id, { getModuleInfo, getModuleIds }) => { const filePath = path.parse(id); const dirPath = filePath.dir .replace(/.*\/src/, "") .replace("/", ""); if ([".css", ".scss", ".less"].includes(filePath.ext)) { return `${dirPath}/style`; } if (/vue&type=template&lang/.test(filePath.name)) { const realName = filePath.name.replace( /\.vue\?vue\&type\=template\&lang/, "" ); return `${dirPath}/${realName}`; } if (dirPath) { return `${dirPath}/${filePath.name}`; } return `${filePath.name}`; }, }, external: [ ...Object.keys(pkg.devDependencies), /@gb\/utils.*/, /node_modules/, ], }, }, });
业务源码
export default function (fileUrl = '') { let file = fileUrl.split('?')[0] let fileName = file.substring(file.lastIndexOf('/') + 1) || '' let suffixLastIndex = fileName.lastIndexOf('.') let name = fileName.substring(0, suffixLastIndex) let suffix = fileName.substring(suffixLastIndex + 1, fileName.length) return { name, suffix } }
异常构建产物
function getUrlToFileSuffix(fileUrl = "") { let file = fileUrl.split("?")[0]; let fileName = file.substring(file.lastIndexOf("/") + 1) || ""; let suffixLastIndex = fileName.lastIndexOf("."); let name = fileName.substring(0, suffixLastIndex); let suffix = fileName.substring(suffixLastIndex + 1, fileName.length); return { name, suffix }; } export { getUrlToFileSuffix as g };
修复方案
问题核心原因有两点:一是配置中minify: "minify"为无效值,构建时默认开启的压缩混淆会重命名导出标识符;二是Rollup输出层未做导出名称保留配置,chunk合并时会自动改写导出名做短名优化。按以下步骤调整配置即可:
- 修正压缩配置,禁止标识符重命名
删除原有无效的minify: "minify"配置,根据使用的压缩工具添加对应保留名称的参数:- 使用默认esbuild压缩(构建速度更快):
build: { minify: "esbuild", esbuild: { keepNames: true, // 保留函数、变量原始声明名称 minifyIdentifiers: false, // 关闭标识符级别的压缩重命名 }, // 其余原有build配置保持不变 }- 使用terser压缩:
build: { minify: "terser", terserOptions: { keep_fnames: true, mangle: { keep_fnames: true, exports: false // 禁止篡改导出项名称 } }, // 其余原有build配置保持不变 } - 补充Rollup输出配置,明确导出规则
在rollupOptions.output节点下添加配置,固定命名导出模式:
rollupOptions: { output: { exports: "named", // 强制使用命名导出规则,不做导出名称改写 // 其余原有output配置(manualChunks、chunkFileNames等)保持不变 }, // external等其余配置保持不变 }
- (可选)开启模块保留配置,适配组件库单文件输出场景
如果需要让构建产物最大程度匹配源码的文件结构,避免多模块合并时的导出映射问题,可以打开之前注释的preserveModules配置:
output: { preserveModules: true, preserveModulesRoot: "src", // 其余output配置保持不变 }
效果验证
配置调整完成后重新执行构建命令,产物中的导出项将保留原始命名,不会再出现单字符重命名的问题。
内容的提问来源于stack exchange,提问作者Mrzhou
相关产品推荐
相关产品推荐

