将模块从CommonJS改为其他格式导致Angular编译或运行异常
问题根源与解决方案:exports is not defined + import解析失败
这问题我之前帮好几个开发者排查过,核心是TypeScript模块输出格式、浏览器环境、模块解析规则三者没对齐,你大概率忽略了这几个关键配置的组合:
1. 必须补上package.json的模块类型标记
浏览器原生环境不认识CommonJS的exports/require,但切换到ES模块后,必须告诉Node.js和浏览器当前项目是ES模块规范——在项目根目录的package.json里加一行:
"type": "module"
这步是很多人漏掉的核心:没有这个标记,即便你tsconfig输出ES模块,Node.js(或依赖Node解析的工具)还是会把文件当成CommonJS处理,导致import语句解析失败。
2. 对齐tsconfig的模块相关配置
不能单独改module字段,要同时调整module、moduleResolution、target三个配置,适配浏览器环境:
{ "compilerOptions": { "target": "ES2020", // 匹配主流浏览器支持的ES版本,别用太旧的ES3/ES5 "module": "ESNext", // 输出浏览器能识别的ES模块格式 "moduleResolution": "bundler", // 如果用Vite/Rollup/Webpack这类打包工具,选这个;原生ES模块用"node16" "outDir": "./dist", // 编译后文件输出目录 "rootDir": "./src", // 源码根目录,保证编译后路径对应 "strict": true, "resolveJsonModule": true, // 如果需要导入JSON文件 "skipLibCheck": true }, "include": ["src/**/*"], "exclude": ["node_modules"] }
- 如果你之前用了
esModuleInterop,在ES模块模式下可以关掉,这个选项是为了兼容CommonJS模块的默认导出,ES模块模式下不需要。
3. 浏览器加载脚本的正确姿势
如果不用打包工具,直接在HTML里引入编译后的JS文件,必须给<script>标签加type="module"属性:
<script type="module" src="./dist/index.js"></script>
没有这个属性,浏览器会把文件当成传统脚本执行,既不认识import,也会因为CommonJS的exports报错。
4. 解决import路径的扩展名问题
移除CommonJS后解析import失败,还有可能是你源码里的导入路径没写全扩展名(比如import utils from './utils')。浏览器原生ES模块要求必须写完整的.js扩展名,而TypeScript默认不会自动补全。
这时候可以:
- 用打包工具(比如Vite)自动处理路径补全;
- 或者在tsconfig里开启
"moduleResolution": "node16",同时在源码里写完整扩展名(比如import utils from './utils.js'),TypeScript会自动映射到对应的.ts文件。
过渡方案:用打包工具抹平差异
如果你的项目里还有不少CommonJS格式的第三方依赖,或者不想手动调整所有导入路径,最省心的方式是用Vite、Rollup这类打包工具:
- 打包工具会自动把ES模块、CommonJS模块统一转换成浏览器能识别的格式;
- tsconfig里保持
module: "ESNext"即可,剩下的交给打包工具处理。
内容的提问来源于stack exchange,提问作者DrDamnit
相关产品推荐
相关产品推荐

