Vite编译文件执行时出现命名空间映射错误如何解决
问题描述
我使用Vite/SWC构建Node.js(NestJS)应用,配置文件如下:
import { defineConfig } from 'vite'; import { VitePluginNode } from 'vite-plugin-node'; import path from 'path'; export default defineConfig({ build: { rollupOptions: { output: { format: 'cjs', entryFileNames: '[name].js' } } }, plugins: [ ...VitePluginNode({ adapter: 'nest', appPath: './src/index.ts', initAppOnBoot: false, tsCompiler: 'swc', swcOptions: { jsc: { parser: { syntax: 'typescript', dynamicImport: true, decorators: true }, baseUrl: path.resolve('.'), paths: { '@libs/*': ['src/libs/*'] }, target: 'es2021', transform: { decoratorMetadata: true } } } }) ], optimizeDeps: { exclude: ['@nestjs/microservices', '@nestjs/websockets'] } });
编译过程可成功完成,但执行编译后的文件时抛出如下错误:
Object.defineProperty(n, k, d.get ? d : { ^ TypeError: Cannot read properties of undefined (reading 'get') at _interopNamespaceDefault (pathToFile/index.js:34:39) at Module.<anonymous> (pathToFile/index.js:48:41) ...
排查后发现问题根源:Rollup生成的_interopNamespaceDefault函数中,当处理process对象的setMaxListeners属性时,Object.getOwnPropertyDescriptor(e, k)返回undefined(因为setMaxListeners是EventEmitter原型链上的属性,而非process自身属性),导致读取d.get时触发类型错误。
解决方法
方案1:标记process为外部模块
修改Vite的Rollup配置,将process标记为外部内置模块,避免Rollup对其进行命名空间转换处理:
export default defineConfig({ build: { rollupOptions: { output: { format: 'cjs', entryFileNames: '[name].js' }, // 告知Rollup process是Node.js内置模块,不参与打包转换 external: ['process'] } }, // ...其他原有配置 });
方案2:调整SWC模块处理配置
在SWC配置中明确指定模块类型为CommonJS,并启用外部辅助函数,减少不必要的转换逻辑:
swcOptions: { jsc: { // ...原有jsc配置 }, externalHelpers: true, module: { type: 'commonjs' } }
方案3:自定义插件修复interop函数
添加自定义Vite插件,重写Rollup生成的_interopNamespaceDefault函数,补充原型链属性的处理逻辑:
import { defineConfig } from 'vite'; import { VitePluginNode } from 'vite-plugin-node'; import path from 'path'; export default defineConfig({ // ...原有配置 plugins: [ ...VitePluginNode({/* 原有插件配置 */}), { name: 'fix-interop-namespace', transform(code, id) { // 仅处理编译后的入口文件 if (id.endsWith('index.js') && code.includes('_interopNamespaceDefault')) { return code.replace( /function _interopNamespaceDefault\(e\) {[\s\S]*?return Object.freeze\(n\);}/, `function _interopNamespaceDefault(e) { const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } }); if (e) { for (const k in e) { if (k !== 'default') { let d = Object.getOwnPropertyDescriptor(e, k); // 处理原型链上的属性 if (!d) { d = { enumerable: true, get: () => e[k] }; } Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: () => e[k] }); } } } n.default = e; return Object.freeze(n); }` ); } return code; } } ] });
方案4:降级依赖版本
该问题属于特定版本Rollup/Vite的interop处理bug,可尝试将Rollup降级到3.x系列,或Vite降级到4.x稳定版本,规避该问题。
内容的提问来源于stack exchange,提问作者Vololodymyr
相关产品推荐
相关产品推荐

