在 TypeScript 中,moduleResolution 决定了 编译器如何查找模块文件路径(即当你 import "foo" 时,TypeScript 怎样找到 foo 对应的文件)。
这个选项在不同项目类型(Node、前端、monorepo)中影响很大。下面是详细对比:
一、可选取值一览(截至 TS 5.6)
| 取值 | 适用环境 | 简介 |
|---|---|---|
classic | 旧版 JS 项目 | 旧的非 Node 模块解析方式(几乎不再推荐) |
node | Node.js (CommonJS 模块) | 模拟 Node.js 的 CommonJS 模块解析逻辑 |
node16 | Node.js (ESM 模块) | 支持 ES 模块、.mts/.cts、package.json 中 "exports" |
nodenext | Node.js (ESM + CommonJS 混合) | 推荐用于现代 Node 项目,兼容性最好 |
bundler | 前端打包器 (Vite、Webpack、esbuild) | 模拟打包器行为,忽略 Node exports 限制 |
classic | 老旧、浏览器直接运行脚本 | 仅用于历史原因,不推荐使用 |
二、主要取值对比表
| 特性 | classic | node | node16 | nodenext | bundler |
|---|---|---|---|---|---|
支持 node_modules | ❌ 否 | ✅ 是 | ✅ 是 | ✅ 是 | ✅ 是 |
支持 "exports" 字段 | ❌ 否 | ❌ 否 | ✅ 是 | ✅ 是 | 🚫 忽略 "exports" 限制(直接解析路径) |
支持 .mts / .cts / .d.mts 等扩展名 | ❌ 否 | ❌ 否 | ✅ 是 | ✅ 是 | ✅ 是 |
| 支持混合 ESM/CJS | ❌ 否 | ⚠️ 有限 | ⚠️ 分开(需匹配文件扩展) | ✅ 是 | ✅ 是 |
支持前端别名路径(例如 #/*、@/*) | ❌ 否 | ❌ 否 | ⚠️ 需配置 | ✅/⚠️ | ✅ 最好支持 |
| 最推荐使用场景 | 旧项目 | Node.js CJS | Node.js ESM | Node.js 通用 | 前端项目(Vite/Webpack) |
三、常见组合(tsconfig 示例)
a) 前端项目(Vite)
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "bundler",
"target": "ESNext"
}
}
b) Node ESM 项目
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "nodenext",
"target": "ES2022"
},
"type": "module"
}
c) Node CJS 项目
{
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "node",
"target": "ES2019"
}
}
四、总结一句话记忆
- 🧓
classic:古董遗产,别碰。 - ⚙️
node:老式 Node.js 项目。 - 🪄
node16:Node.js 的官方 ESM 规则。 - 🧬
nodenext:ESM + CJS 混合模式,Node 项目首选。 - 🎨
bundler:为打包器而生,前端项目首选。