Node 的 require 与 import 如何解析模块?为什么 ESM 常要求扩展名?
先理解原理和示例,再练习完整口述与追问。
回答要点
路径、包名、内置模块;CJS 历史补全;ESM 按 URL 与包 exports;package type;版本互操作。
原理拆解
CommonJS require 根据请求形式区分内置、相对/绝对路径与包解析,历史上支持特定扩展名和目录入口的查找,结果按解析文件缓存。原生 ESM 的相对/绝对 specifier 通常要求明确扩展名,不自动照搬 require 的目录和补全规则;包名则可受 package.json 的 exports 等约束。
.cjs 明确 CommonJS,.mjs 明确 ESM,.js 受相关 package type 等环境规则影响。打包器可能支持别名和自动补全,那是构建工具提供的解析,不代表服务器原生运行也一定支持。
示例与推演
本项目的 require('./library.cjs') 可直接运行;若改为 ESM,import './library' 不能因为编辑器能跳转就认定 Node 能解析。使用私有包内部路径也可能被 exports 阻止,应该依赖公开入口而非硬钻 node_modules 文件。
易错点
Node16 与新版本 require(ESM) 支持不同;循环依赖和 CJS/ESM 默认导入不能一概类比。运行时别名还需真实解析支持。
参考回答可直接练习口述
我先确认模块格式与 Node 版本,再按原生解析规则检查路径和包入口。ESM 明确扩展名能减少历史猜测,构建工具的补全不能直接搬到 Node;exports 和互操作也按版本核对。