源本科技 | 码上会

Node.js 模块加载机制

2026/04/10
2
0

引言

模块加载机制是 Node.js 遵循 CommonJS 规范 实现的核心规则,定义了使用 require() 导入模块时,系统识别、查找、加载、执行模块的完整流程。 Node.js 会按照缓存优先、优先级分级、逐级向上查找的逻辑加载模块,同时自带缓存机制避免重复执行,极大提升了程序运行效率,保障了模块化开发的稳定性。

优先从缓存加载

Node.js 对已加载的模块会进行永久缓存,这是模块加载的第一优先级规则。 无论使用 require() 加载多少次同一个模块,模块代码只会执行一次,后续加载直接读取缓存结果,不会重复执行模块代码。

核心特性

  1. 缓存范围:内置模块、自定义模块、第三方模块全部支持缓存

  2. 缓存标识:以模块的绝对路径作为唯一缓存 key

  3. 优势:避免重复执行代码,提升加载效率,节约系统资源

代码验证

// 第一次加载:执行模块代码,并存入缓存
require('./test.js');
// 第二次加载:直接读取缓存,模块内部代码不会再次执行
require('./test.js');

内置模块加载机制

内置模块是 Node.js 官方提供的核心模块(如 fspathhttp),加载优先级仅次于缓存,是所有模块中优先级最高的业务模块。

核心规则

  1. 加载标识符直接写模块名:require('fs')

  2. 优先级最高:即使 node_modules 中存在同名第三方包,也会优先加载官方内置模块

  3. 无需安装、无需配置路径,直接加载

示例代码

// 永远加载 Node.js 内置 fs 模块
const fs = require('fs');
const path = require('path');

自定义模块加载机制

自定义模块是开发者编写的 .js/.json/.node 文件,必须使用相对路径标识./../ 开头)。

核心规则

  1. 路径必填:不写 .//../,Node.js 会误识别为内置模块或第三方模块

  2. 扩展名可省略:Node.js 会自动按顺序补全扩展名尝试加载

  3. 补全顺序:精确文件名 → .js.json.node → 抛出错误

加载示例

// 完整写法(推荐)
const utils = require('./utils.js');
// 省略扩展名:自动补全尝试加载
const utils = require('./utils');

常见错误

// 错误写法:缺少相对路径标识符,加载失败
const utils = require('utils');

第三方模块加载机制

第三方模块(npm 安装的包)既不是内置模块,也不以相对路径开头,Node.js 会按照逐级向上查找 node_modules 的规则加载。

核心查找流程

  1. 当前文件所在目录node_modules 中查找

  2. 未找到,则进入父级目录node_modules 查找

  3. 重复向上遍历,直到文件系统根目录

  4. 全部查找失败,抛出 Cannot find module 错误

查找路径示例

当前文件路径:C:/project/src/index.js 加载模块:require('moment') 查找顺序:

  1. C:/project/src/node_modules/moment

  2. C:/project/node_modules/moment

  3. C:/node_modules/moment

  4. 查找失败,报错

示例代码

// 加载第三方包,无需路径,直接写包名
const moment = require('moment');
const _ = require('lodash');

目录作为模块

Node.js 支持直接将一个目录当作模块加载,无需指定具体文件,系统会按照固定规则查找入口文件。

完整加载规则

  1. 读取目录下的 package.json 文件,查找 main 字段指定的入口文件

  2. 若无 package.jsonmain 字段无效,自动尝试加载目录下的 index.js

  3. 以上两步均失败,抛出模块找不到错误

目录结构示例

myModule/
├── index.js
└── package.json

package.json 配置:

{
  "name": "my-module",
  "version": "1.0.0",
  "main": "./index.js"
}

加载代码

// 直接加载目录,自动匹配入口文件
const myModule = require('./myModule');

补充说明

模块加载优先级

  1. 缓存模块(最高优先级)

  2. 内置模块

  3. 自定义模块

  4. 第三方模块(逐级向上查找)

  5. 目录模块(按规则匹配入口文件)

常见问题

  1. 加载自定义模块时省略 ./,导致加载失败

  2. 认为多次 require() 会重复执行模块代码

  3. 目录模块缺少 index.jspackage.json,导致加载报错

模块加载优势

  • 缓存机制:避免重复执行,提升性能

  • 优先级机制:保障内置模块的安全性

  • 自动补全:简化模块导入写法

  • 目录模块化:支持封装复杂功能模块


总结

  1. 缓存优先:模块首次加载后会被缓存,多次导入不重复执行

  2. 优先级:缓存 > 内置模块 > 自定义模块 > 第三方模块

  3. 自定义模块:必须用 .//../ 开头,扩展名可自动补全

  4. 第三方模块:从当前目录逐级向上查找 node_modules

  5. 目录模块:优先读取 package.jsonmain 字段,其次加载 index.js