前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库Node.js 区分 ESM 与 CommonJS type 字段
JavaScript模块与语言机制

Node.js 怎么判断一个 .js 文件是 CommonJS 还是 ESM?type 字段管什么?

先看扩展名,.mjs 按 ESM,.cjs 按 CommonJS,这两个不看任何配置。.js 文件则往上找最近的 package.json,"type": "module" 就按 ESM,"type": "commonjs" 或者没写就按 CommonJS。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#模块与语言机制
先看核心答案读代码示例
理解线索

Node.js 判断格式的顺序

  1. 扩展名.mjs、.cjs 直接决定,优先级最高
  2. type 字段对 .js 生效,从文件所在目录往上找最近的 package.json
  3. 默认值找到的 package.json 没写 type,按 CommonJS 处理

判断依据是「最近的」package.json,不是项目根目录那个。子目录里放一个只有 {"type": "commonjs"} 的 package.json,就能让这个目录下的 .js 单独按 CommonJS 处理,很多库就是这样同时发布两种格式的。

核心回答

先记住这个答案

Node.js 先看扩展名:.mjs 一定按 ESM 加载,.cjs 一定按 CommonJS 加载,不受任何配置影响。只有 .js 需要额外判断:从文件所在目录往上找最近的 package.json,里面写了 "type": "module" 就按 ESM,写了 "type": "commonjs" 或者根本没写就按 CommonJS。type 字段就是给 .js 文件指定默认格式的开关,默认值是 CommonJS,这是为了不破坏大量已有的老包。

  • .mjs 是 ESM,.cjs 是 CommonJS
  • .js 还要看包的 type 设置
  • 不要仅凭扩展名猜 .js 模块类型
  • type 只管本包内的 .js,不影响依赖包

同一个文件,换个配置就报错

在一个目录里放一个 c.js,内容是 CommonJS 写法。

改了 type 以后Shell
# c.js 内容:const path = require('path'); console.log(typeof path)

echo '{}' > package.json
node c.js
# object,没写 type,按 CommonJS 运行

echo '{"type":"module"}' > package.json
node c.js
# ReferenceError: require is not defined in ES module scope

mv c.js c.cjs && node c.cjs
# object,.cjs 不看 type

第二次运行时文件内容没变,只是 package.json 多了 "type": "module",c.js 就被当成了 ESM,而 ESM 里没有 require、module、exports、__dirname 这些变量。改成 .cjs 扩展名后又能跑了,因为扩展名的优先级更高。 反过来也一样:没有 type 字段的项目里,.js 文件写 import 语句,传统上会报 Cannot use import statement outside a module。我在 Node 22 上实测,它会先检测到 ESM 语法,改按 ESM 重新解析,同时打印一条警告,建议你在 package.json 里加上 "type": "module"。这个检测只是兜底,有额外开销,正式项目还是应该写清楚。

两种格式怎么互相引用

新项目一般整体用 ESM,但依赖里还有大量 CommonJS 包,互相引用的规则要清楚。

ESM 引 CommonJS,CommonJS 引 ESM
ESM 导入 CommonJS 一直都可以,module.exports 会作为默认导出,Node.js 也会尽量静态分析出具名导出,但分析不出来的只能从默认导出上取。 CommonJS 引 ESM 过去只能用 await import(),因为 require 是同步的,而 ESM 可以包含顶层 await。较新的 Node.js 版本支持直接 require 一个没有顶层 await 的 ESM 文件,但老版本不行,要兼容老环境的库仍然只能提供两份产物。
回答前,多想一步

容易答错的地方

以为 type 看的是项目根目录的 package.json
看的是离文件最近的那一个。monorepo 里每个子包有自己的 package.json,各自的 type 各管各的。构建产物目录里放一个小的 package.json 覆盖格式,也是常见做法。
以为设置 type 会影响 node_modules 里的依赖
依赖包有自己的 package.json,按它自己的 type 解析。你把项目改成 "type": "module",不会让某个 CommonJS 依赖突然变成 ESM。
忘了配置文件也受影响
项目改成 "type": "module" 后,根目录下用 module.exports 写的 .eslintrc.js、postcss.config.js、jest.config.js 会立刻报错。改名成 .cjs,或者改用 export default 写法。
试着用自己的话回答

面试官还会怎么问?

TypeScript 里怎么对应?

TypeScript 有对应的 .mts 和 .cts 扩展名,编译后分别产出 .mjs 和 .cjs。.ts 文件编译成什么格式,在 module 设为 nodenext 时同样取决于最近的 package.json 的 type。

node -e 执行的代码按什么格式?

字符串输入和标准输入默认按 CommonJS。可以用 --input-type=module 指定按 ESM 执行。

为什么不直接把默认值改成 ESM?

npm 上有海量没写 type 字段的 CommonJS 包,默认值一改它们全部会坏。所以 Node.js 选择保持默认 CommonJS,让新项目显式声明 "type": "module"。

从一道题,走向一组知识

把知识连起来

模块与语言机制

package.json 的 exports 字段怎么控制包的入口?条件导出按什么顺序匹配?

type 决定文件按什么格式解析,exports 决定包被导入时给出哪个文件,库发布双格式时两个字段要一起配。

模块与语言机制

用 type="module" 加 nomodule 给老浏览器降级,要注意哪些坑?

Node.js 靠扩展名和 type 区分模块格式,浏览器则靠 type="module" 和 nomodule 两个属性区分。

参考资料

  • JavaScript:模块与语言机制参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 同一个文件,换个配置就报错
  3. 两种格式怎么互相引用
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑