TypeScript 中的 nodenext 与 bundler
对比 nodenext 与 bundler 两种模块解析思路,解释它们分别更接近 Node.js 还是现代 bundler,以及各自适用项目类型。
#tech / dev
#resource / typescript
#type / concept
#status / growing
[!info] related notes
- 所属 MOC: TypeScript MOC
- 配置入口: tsconfig 使用详解
- 前置概念: TypeScript 中的 module, TypeScript 中的 moduleResolution
- 关系笔记: Node、bundler 与 TypeScript 模块解析的关系
TypeScript 中的 nodenext 与 bundler
一句话定义
nodenext:尽量模拟现代 Node.js 自己的模块解析规则bundler:尽量模拟 Vite / Webpack / Rollup / esbuild 等现代 bundler 的模块解析规则
核心机制 / 工作原理
nodenext
更接近真实 Node.js 运行时,尤其要处理:
- CommonJS 与 ESM 并存
package.json typeexports/imports- 相对路径扩展名要求
bundler
更接近现代 bundler 开发体验,通常支持:
- 无扩展名相对路径
exports/importsnode_modules- 更宽松的相对路径解析习惯
最小例子 / 最小场景
bundler
在很多 bundler 项目里,这样常见且可接受:
import { foo } from "./foo";
nodenext
如果当前文件会按 Node ESM 规则运行,更常需要写成:
import { foo } from "./foo.js";
即使源码文件实际是 foo.ts,TypeScript 也会通过扩展名替换机制理解它。
常见适用场景
更适合 nodenext
- Node 后端
- CLI
- 直接
tsc编译后交给 Node 跑的项目 - 发布给别人使用的 npm library
更适合 bundler
- Vite / Webpack / Rollup / esbuild 前端项目
- TypeScript 只做类型检查,真正 emit 交给 bundler 的项目
边界与易混淆点
bundler 更宽松,不代表更适合发布库
TypeScript 官方提醒过:如果你要发布 npm library,bundler 可能会隐藏那些“不经过 bundler 的消费者”在 Node 环境里会踩到的兼容问题。
nodenext 不是“只适合 ESM”
它描述的是现代 Node 的双模块系统,不是“单纯只输出 ES modules”。
TypeScript 5.2 之后更强调 module 与 moduleResolution 要匹配
例如:
module: "nodenext"通常就该搭配moduleResolution: "nodenext"module: "esnext"常和moduleResolution: "bundler"一起出现
参考信息
- TSConfig
moduleResolution: https://www.typescriptlang.org/tsconfig/moduleResolution.html - TSConfig
module: https://www.typescriptlang.org/tsconfig/module - TypeScript 5.2 Release Notes: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html
- TypeScript 5.0 Release Notes: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html