Node.js 是怎么找到模块的?你知道吗?

开发 前端
首先分析标识符的风格,如果是不是路径的写法,我们会先找 Node.js 内置的包有没有匹配的,如果匹配,就导入对应模块,比如 require('http') 就能拿到一个 http 对象,可用于创建 web 服务等功能。

大家好,我是前端西瓜哥,今天我们来看看 Node.js 模块查找的原理。

模块种类

模块有三种来源。

  1. 核心模块:Node.js 内置的包。比如 http、fs、path。
  2. 自定义模块:NPM 包。比如 axios、express,位于 node_modules 目录下的同名目录,并通过 package.json 的 main 字段指定入口文件。
  3. 文件模块:项目自己的模块文件,使用路径的写法。包括相对路径(比如 "./utils")和绝对路径(比如 "/Users/xigua/project/utils")。

需要注意的是,"a/b" 这种不属于路径写法,它属于前两种,比如 "fs/promises"、"@babel/core"。

这里给一个例子:

const http = require('http'); // Node.js 内置包
const { defaultContent } = require('./default'); // 开发者自己写的模块文件
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(defaultContent);
}).listen(3200);

模块查找

我们使用 require() 方法,传入一个字符串标识符,模块查找的旅途就开始了。

核心模块

首先分析标识符的风格,如果是不是路径的写法,我们会先找 Node.js 内置的包有没有匹配的,如果匹配,就导入对应模块,比如 require('http') 就能拿到一个 http 对象,可用于创建 web 服务等功能。

NPM 包

如果不匹配,会在当前文件的目录下,找 node_modules 目录,看里面有没有对应的包。如果找不到,就继续往父目录找,直到根目录。如果找不到,会报 Cannot find module '包名' 的错误。

文件模块

包通常是一个文件夹,里面会有 package.json 文件,Node.js 会提取其中 main 字段对应的文件作为模块文件。如果没有,就依次查找该目录下的 index.js、index.json、index.node 文件。

需要查找的目录可以通过 module.paths 变量得到。

如果你熟悉 JavaScript 的原型链,你会发现它们非常相似,可以做类比以加深理解。

如果标识符是路径,会通过计算得到一个绝对路径,然后找到的是个目录,同上面找 npm 包的逻辑。

要是找不到,就加上后缀再找。后缀按顺序添加为:.js 、.json、.node,找到就立即返回。若一个文件没有后缀但被匹配到了,它会被当作 js 文件。

上面没说缓存的情况,其实我们会对模块做缓存,下面详细说明一下。

模块缓存

每当加载一个模块后,这个模块就会被缓存起来。

你可以在随意一个文件中输入得到缓存的内容,是一个哈希表,key 为模块的绝对路径,确保缓存命中,value 则是模块对象。

const { Module } = require("module");
console.log(Module._cache);

也能用  require.cache 变量拿到,它和 Module._cache 指向同一个对象。

Node.js 内置的模块也需要缓存,但它不会记录到 Module._cache 中,而是保存在 Module.

下面是一个例子,index.js 导入了 a.js,a.js 下引入了 lodash.get 包,模块缓存结果为:

图片

因为缓存的存在,所以 一个模块文件只会被执行一次,然后将 module.exports 缓存下来。

之后被多次导入,不会再执行这个模块文件,而是直接取出对应的 module.exports。

总结

画了个流程图,丢掉了一些细节(路径定位到目录后的逻辑)。

图片

责任编辑:姜华 来源: 前端西瓜哥
相关推荐

2011-12-09 11:16:48

Node.js

2024-02-19 00:00:00

Docker轻量级容器

2020-12-30 11:22:11

Node.js前端模块

2021-11-16 08:51:29

Node JavaScript变量类型

2023-12-20 08:23:53

NIO组件非阻塞

2024-06-20 08:06:30

2022-11-28 00:04:17

2024-01-15 12:16:37

2024-04-26 09:03:31

Node.jsCurrent发布版

2024-10-05 00:00:00

HTTPS性能HTTP/2

2011-09-02 14:47:48

Node

2021-09-26 05:06:04

Node.js模块机制

2023-06-20 19:35:00

Node.js工具

2024-07-30 08:22:47

API前端网关

2024-11-08 09:48:38

异步编程I/O密集

2024-10-24 08:47:12

2024-03-19 08:01:54

服务熔断软件设计模式微服务

2024-02-19 07:44:52

虚拟机Java平台

2020-04-15 15:48:03

Node.jsstream前端

2023-01-09 08:00:41

JavaScript闭包
点赞
收藏

51CTO技术栈公众号