TypeScript 中的 nodenext 与 bundler

对比 nodenext 与 bundler 两种模块解析思路,解释它们分别更接近 Node.js 还是现代 bundler,以及各自适用项目类型。

#tech / dev #resource / typescript #type / concept #status / growing

[!info] related notes

TypeScript 中的 nodenext 与 bundler

一句话定义

  • nodenext:尽量模拟现代 Node.js 自己的模块解析规则
  • bundler:尽量模拟 Vite / Webpack / Rollup / esbuild 等现代 bundler 的模块解析规则

核心机制 / 工作原理

nodenext

更接近真实 Node.js 运行时,尤其要处理:

  • CommonJS 与 ESM 并存
  • package.json type
  • exports / imports
  • 相对路径扩展名要求

bundler

更接近现代 bundler 开发体验,通常支持:

  • 无扩展名相对路径
  • exports / imports
  • node_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 之后更强调 modulemoduleResolution 要匹配

例如:

  • module: "nodenext" 通常就该搭配 moduleResolution: "nodenext"
  • module: "esnext" 常和 moduleResolution: "bundler" 一起出现

参考信息

创建于 2026/5/15 更新于 2026/5/27