
1. 理解commonjsOptions.include的应用场景在Vite项目的构建配置中commonjsOptions.include参数常常让开发者感到困惑。这个配置项本质上是为了解决项目中混合使用ES模块和CommonJS模块时的兼容性问题。当你的项目依赖链中存在CommonJS格式的包时Vite需要明确知道哪些模块需要被特殊处理。常见需要配置include的情况包括项目依赖的第三方库明确使用module.exports语法从旧版Node.js项目迁移过来的遗留代码使用了未正确声明模块类型的npm包需要处理动态require的复杂场景2. 配置原理深度解析2.1 Vite的模块处理机制Vite在开发环境下使用浏览器原生ES模块而在生产构建时默认使用Rollup打包。Rollup原生支持ES模块但对CommonJS模块需要借助rollup/plugin-commonjs进行转换。这个转换过程就是commonjsOptions配置发挥作用的地方。include参数实际上是在告诉Rollup只有这些指定的模块需要被CommonJS插件处理。这种定向处理的好处是避免对已经是ES模块的代码进行不必要的转换减少构建时的处理开销防止双重转换导致的奇怪问题2.2 include的典型配置模式在实际项目中include通常配置为数组形式支持以下几种匹配模式// vite.config.js export default { build: { commonjsOptions: { include: [ // 明确指定包名 lodash, react-draggable, // 使用通配符匹配 node_modules/react-*/**, // 正则表达式匹配 /node_modules\/.*cjs/, // 本地文件匹配 src/legacy/** ] } } }3. 实战配置指南3.1 何时必须配置include以下情况必须显式配置include控制台出现require is not defined错误时使用Vite插件如vitejs/plugin-react时遇到模块加载问题项目依赖树中包含未转译的CommonJS模块需要优化构建性能减少不必要的模块转换3.2 配置的最佳实践精确匹配优于模糊匹配尽量指定具体的包名而非宽泛的通配符逐步添加而非全部包含通过构建错误提示逐步添加必要模块性能考量大型项目应该将常用CJS依赖预先配置开发/生产环境差异某些依赖可能只需要在生产环境转换// 推荐的生产环境配置示例 export default { build: { commonjsOptions: { include: [ // 已知的CJS依赖 react-dnd, react-draggable, lodash, // UI库的子组件 antd/es/date-picker, // 本地遗留代码 src/utils/legacy.js ], exclude: [node_modules/**.mjs] // 明确排除ES模块 } } }4. 常见问题排查4.1 典型错误场景未包含必要模块症状运行时出现require is not defined解决检查报错模块是否在include列表中过度包含导致问题症状ES模块被错误转换导致功能异常解决缩小include范围或添加exclude动态require问题症状条件加载的模块未正确处理解决确保动态路径在include通配范围内4.2 调试技巧使用vite --debug查看详细的模块转换日志在rollupOptions中增加输出日志plugins: [ commonjs({ include: [...], transformMixedEsModules: true, debug: true }) ]检查最终产物的模块格式是否正确5. 性能优化建议合理的include配置可以显著提升构建性能基准测试比较不同配置下的构建时间依赖分析使用npm ls查看完整的依赖树渐进式优化初始阶段可以配置较宽泛的include根据构建日志逐步精确化配置最终锁定到具体的包和文件对于大型项目建议将commonjsOptions配置单独提取为文件便于维护和团队共享// commonjs-deps.js module.exports [ react-dnd, react-draggable, lodash, // 其他已知CJS依赖 ] // vite.config.js import cjsDeps from ./commonjs-deps export default { build: { commonjsOptions: { include: cjsDeps } } }6. 与其他配置的协同commonjsOptions.include需要与以下配置协同工作optimizeDeps.include用于开发环境的预构建与build.commonjsOptions.include有部分重叠rollupOptions.external防止某些依赖被打包需要与include配置保持一致build.lib模式库模式需要更精确的模块控制通常需要更严格的include配置一个综合配置示例export default { optimizeDeps: { include: [react, react-dom] // 开发环境预构建 }, build: { commonjsOptions: { include: [react-dnd, lodash], // 生产环境CJS转换 exclude: [node_modules/**.mjs] }, rollupOptions: { external: [react], // 外部化依赖 plugins: [ // 其他Rollup插件 ] } } }7. 版本升级注意事项随着Vite版本更新commonjsOptions的行为可能有变化Vite 3.x → 4.xCommonJS转换策略更智能需要的显式配置可能减少Vite 4.x → 5.x对混合模块的支持更好但仍建议保留关键配置升级后建议先移除所有include配置测试构建根据报错逐步添加必要配置比较新旧版本的构建产物差异8. 项目迁移场景处理从其他构建工具迁移到Vite时需要特别注意Webpack迁移Webpack对CJS更宽容需要仔细检查所有非ESM依赖Parcel迁移Parcel的自动转换可能掩盖问题需要显式声明所有CJS依赖UMD库集成UMD通常需要作为CJS处理可能需要额外配置transformMixedEsModules迁移检查清单运行构建并记录所有CJS相关警告对每个警告分析是否需要添加到include测试运行时行为是否与源构建一致9. 高级应用场景9.1 微前端集成在微前端架构中子应用可能使用不同的模块系统// 主应用配置 export default { build: { commonjsOptions: { include: [ // 子应用暴露的CJS模块 micro-app-1/dist/entry.cjs, micro-app-2/dist/entry.js ] } } }9.2 条件性包含根据环境变量动态调整includeexport default { build: { commonjsOptions: { include: [ lodash, ...(process.env.USE_LEGACY ? [legacy-module] : []) ] } } }9.3 插件开发开发Vite插件时处理CJS依赖export default function myPlugin() { return { name: my-plugin, config(config) { config.build.commonjsOptions.include [ ...(config.build.commonjsOptions.include || []), my-plugin/deps ] } } }10. 工具链集成10.1 与TypeScript配合当使用TypeScript时需要确保tsconfig.json的module设置与Vite配置一致// tsconfig.json { compilerOptions: { module: ESNext, moduleResolution: node } }10.2 与ESLint配合配置ESLint识别两种模块语法// .eslintrc.js module.exports { rules: { import/no-commonjs: off // 允许CJS语法 } }10.3 与测试工具配合测试环境可能需要不同的配置// vitest.config.js import { defineConfig } from vitest/config import viteConfig from ./vite.config export default defineConfig({ ...viteConfig, test: { deps: { inline: [react-dnd] // 测试环境特殊处理 } } })11. 长期维护建议文档化配置决策为每个include项添加注释说明原因定期审查依赖使用npm outdated检查依赖更新建立自动化检查在CI中添加模块格式验证团队知识共享记录常见问题的解决方案配置文档示例/** * CommonJS模块包含配置 * * react-dnd: 2.x版本仍使用CJS * lodash: 兼容旧版导入方式 * legacy-module: 内部遗留代码待重构 */ const commonjsIncludes [ react-dnd, lodash, src/legacy/** ]