Node.js的require是一套有顺序、有缓存、有路径解析的模块加载系统:先查内置模块,再按相对/绝对路径或node_modules逐级查找,命中后缀优先级为.js/.json/.node;模块首次加载后缓存于require.cache,后续直接返回;导出本质是module.exports对象,exports仅是其引用别名。

Node.js 的 require 不是简单地读文件执行,而是一套有顺序、有缓存、有路径解析的模块加载系统。
模块查找与路径解析规则
当你写 require('./utils') 或 require('lodash') 时,Node.js 会按固定顺序尝试定位模块文件:
- 如果是内置模块(如
fs、path),直接返回,不走文件系统 - 以
./、../或/开头:按相对或绝对路径查找,依次尝试.js、.json、.node后缀(.js优先) - 不带路径前缀(如
require('express')):从当前文件所在目录的node_modules开始向上逐级查找,直到根目录或磁盘根路径 - 找到
package.json且含"main"字段,则加载其指定文件;否则默认找index.js
模块缓存机制(require.cache)
每个模块第一次被 require 后,其导出对象(module.exports)会被缓存在 require.cache 中,后续相同路径的 require 都直接返回缓存值,不会重新执行模块代码。
这意味着:
立即学习“Java免费学习笔记(深入)”;
- 模块是单例的——多次
require同一文件,得到的是同一个对象引用 - 修改
require.cache可强制重新加载(开发时热重载常用,但生产慎用):delete require.cache[require.resolve('./config.js')]; - 循环依赖时,缓存让模块能拿到对方“已初始化一半”的导出对象,而非报错退出
CommonJS 模块导出本质
require 加载的是 module.exports 对象,不是 exports 变量本身:
-
exports.a = 1等价于module.exports.a = 1—— 安全 -
exports = { a: 1 }会断开exports与module.exports的引用,导致模块实际导出为空对象 —— 常见陷阱 - 想完全替换导出内容,应直接赋值
module.exports = { a: 1 }或函数/类
ESM 与 CommonJS 互操作(Node.js ≥12)
Node.js 支持 .mjs、type: "module" 或 --experimental-modules 启用 ES 模块,但 require 仍属 CommonJS 体系:
-
require()不能直接加载纯 ESM 文件(会报错ERR_REQUIRE_ESM) -
import()动态导入可加载 CommonJS 模块,自动提取default(即module.exports) -
createRequire(import.meta.url)可在 ESM 文件中创建兼容的require函数
理解 require 的路径、缓存和导出逻辑,能帮你避开循环引用、热更新失效、模块未更新等典型问题。它不是黑盒,而是可预测、可调试的系统。










