node模块查找策略

embedded/2025/2/6 1:39:37/

在路径 Y 中引入 X 模块:

  1. 如果 X 是核心模块

    a. 返回核心模块

    b. 停止

  2. 如果 X 以 / 开头

    a. 将 Y 设置为文件系统根目录

  3. 如果 X 以 .//../ 开头

    a. LOAD_AS_FILE(Y + X)

    b. LOAD_AS_DIRECTORY(Y + X)

    c. THROW “not found”

  4. 如果 X 以 # 开头

    a. LOAD_PACKAGE_IMPORTS(X, dirname(Y))

  5. LOAD_PACKAGE_SELF(X, dirname(Y))

  6. LOAD_NODE_MODULES(X, dirname(Y))

  7. 抛出 “not found” 错误

LOAD_AS_FILE(X)

  1. 如果 X 是一个文件,则按照其文件扩展名格式加载 X。 停止

  2. 如果 X.js 是一个文件
    a. 找到距离 X 最近的包作用域 SCOPE。
    b. 如果没有找到 scope

    1. MAYBE_DETECT_AND_LOAD(X.js)

    c. 如果 SCOPE/package.json 包含 type 字段

     1. 如果 `type` 字段为 `module` ,则将 X.js 作为 ECMAScript 模块加载。停止。2. 如果 `type` 字段为 `commonjs` ,则将 X.js 作为 commonjs 模块加载。停止。
    

    d. MAYBE_DETECT_AND_LOAD(X.js)

  3. 如果 X.json 是一个文件,则将 X.json 加载为一个 JavaScript 对象。停止。

  4. 如果 X.node 是一个文件,则将 X.node 作为二进制插件加载。停止。

LOAD_INDEX(X)

  1. 如果 X/index.js 是一个文件
    a. 找到距离 X 最近的包作用域 SCOPE。
    b. 如果没有找到 scope, 则将 X/index.js 作为 commonjs 模块加载。停止。
    c. 如果 SCOPE/package.json 包含 type 字段
    1. 如果 type 字段为 module ,则将 X/index.js 作为 ECMAScript 模块加载。停止。
    2. 如果 type 字段为 commonjs ,则将 X/index.js 作为 commonjs 模块加载。停止。
  2. 如果 X/index.json 是一个文件,则将 X/index.json 加载为一个 JavaScript 对象。停止。
  3. 如果 X/index.node 是一个文件,则将 X/index.node 作为二进制插件加载。停止。

LOAD_AS_DIRECTORY(X)

  1. 如果 X/package.json 是一个文件
    a. 解析 X/package.json ,查找 main 字段。
    b. 如果 main 是一个假值,则跳到第 2 步
    c. let M = X + (json main field)
    d. LOAD_AS_FILE(M)
    e. LOAD_INDEX(M)
    f. LOAD_INDEX(X) DEPRECATED
    g. THROW “not found”
  2. LOAD_INDEX(X)

LOAD_PACKAGE_IMPORTS(X, DIR)

  1. 找到与 DIR 最近的包作用域 SCOPE。
  2. 如果没有找到 scope,返回。
  3. 如果 SCOPE/package.json 中的 importsnullundefined,则返回。
  4. let MATCH = PACKAGE_IMPORTS_RESOLVE(X, pathToFileURL(SCOPE), [“node”, “require”])
  5. RESOLVE_ESM_MATCH(MATCH).

LOAD_PACKAGE_SELF(X, DIR)

  1. 找到与 DIR 最近的包作用域 SCOPE。
  2. 如果没有找到 scope,返回。
  3. 如果 SCOPE/package.json 中的 exportsnullundefined,则返回。
  4. 如果 SCOPE/package.json 中的 name 不是 X 的第一个部分,则返回。
  5. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(SCOPE), “.” + X.slice(“name”.length), `package.json` “exports”, [“node”, “require”])
  6. RESOLVE_ESM_MATCH(MATCH)

LOAD_NODE_MODULES(X, START)

  1. let DIRS = NODE_MODULES_PATHS(START)
  2. for each DIR in DIRS:
    a. LOAD_PACKAGE_EXPORTS(X, DIR)
    b. LOAD_AS_FILE(DIR/X)
    c. LOAD_AS_DIRECTORY(DIR/X)

RESOLVE_ESM_MATCH(MATCH)

  1. let RESOLVED_PATH = fileURLToPath(MATCH)
  2. 如果 RESOLVED_PATH 中的文件存在,则按其扩展名格式加载 RESOLVED_PATH。停止。
  3. THROW “not found”

MAYBE_DETECT_AND_LOAD(X)

  1. 如果 X 解析为 CommonJS 模块,则将 X 加载为 CommonJS 模块。停止。

  2. 否则,如果启用了--experimental-require-module选项,并且 X 的源代码可以被解析为 ECMAScript 模块

    a. 加载 X 为 ECMAScript 模块。停止。

  3. 在 1 步中抛出尝试将 X 解析为 CommonJS 时的 SyntaxError,停止。

NODE_MODULES_PATHS(START)

  1. let PARTS = path split(START)
  2. let I = count of PARTS - 1
  3. let DIRS = []
  4. while I >= 0,
    a. if PARTS[I] = “node_modules” CONTINUE
    b. DIR = path join(PARTS[0 … I] + “node_modules”)
    c. DIRS = DIR + DIRS
    d. let I = I - 1
  5. return DIRS + GLOBAL_FOLDERS

模块查找策略粗略图解

graph TB
A(模块查找策略) --> B{是否以 ./ 或 ../ 开头}
B --是--> C{是否带文件扩展名}
C --是--> D{根据路径查找文件}
C --否--> E{加上 .js 或 .json 
后缀查找文件}
D --找到--> I(成功)
D --找不到--> J(失败)
E --找到--> F(成功)
E --找不到--> G{当成文件夹查找文件夹内的package.json 文件
}
G --找到--> H{是否有 main 字段}
H --是--> M{根据 main 字段查找文件}
H --否--> L
M --找到--> N(成功)
M -- 找不到--> O(失败)
G --找不到--> L{文件夹内是否有inexd.js 文件
}
L --找到--> P(成功)
L --找不到--> Q(失败)B --否--> R{是否为核心模块}
R --是--> S(成功)
R --否--> T(进入 node_module 文件夹查找)
T --> E
Created with Raphaël 2.3.0 模块查找策略开始 是否以 ./ 或 ../ 开头 是否带文件扩展名 根据路径查找文件 成功 失败 加上 .js 或 .json 后缀查找文件 成功 当成文件夹 查找文件夹内的 package.json 文件 是否有 main 字段 根据 main 字段查找文件 成功 失败 文件夹内是否有 index.js 文件 成功 失败 是否为核心模块 成功 进入 node_module 文件夹查找 yes no yes no yes no yes no yes no yes no yes no yes no yes no

http://www.ppmy.cn/embedded/159894.html

相关文章

linux 进程补充

环境变量 基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如:我们在编写C/C代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪 里,但是照样可以链接成功&#…

基于python的体育新闻数据可视化及分析

项目 :北京冬奥会体育新闻数据可视化及分析 摘 要 随着社会的不断进步与发展,新时代下的网络媒体获取的信息也更加庞大和繁杂,相比于传统信息来源更加难以分析和辨别,造成了新时代媒体从业者撰写新闻的难度。在此背景下&#xff…

Mac电脑上好用的免费截图软件

在Mac电脑上,有许多免费且功能强大的截图软件可供选择。以下是几款备受推荐的免费截图工具: iShot 功能:iShot是一款免费的截图工具,支持多种截图方式,包括长截图、延时截图、滚动截图、窗口截图、区域截图等。此外&am…

应对现代电子商务的网络威胁—全面安全战略

在当今高度数字化的世界,电子商务企业面临的网络威胁比以往任何时候都更复杂和全球化。不再仅仅是简单的恶意软件或DDoS攻击,如今的威胁来源于复杂的黑客组织、精心设计的定向攻击,甚至是国家支持的网络犯罪活动。企业级电商平台,…

2025-2-3-sklearn学习(50) (51) 完结篇 零落成泥碾作尘,只有香如故。

文章目录 sklearn学习(50) & (51) 完结篇sklearn学习(50) 选择正确的评估器(estimator)sklearn学习(51) 外部资源,视频和谈话51.1 Scientific Python 的新手?51.2 外部教程51.3 视频 sklearn学习(50) & (51) 完结篇 文章参考网站: h…

5 长度和距离计算模块(length.rs)

这段代码定义了一个泛型结构体 Length<T, Unit>&#xff0c;用于表示一维长度&#xff0c;其中 T 表示长度的数值类型&#xff0c;而 Unit 是一个编译时检查单位一致性的占位符类型&#xff0c;不会用于运行时表示长度的值。这个设计允许开发者在编译阶段确保不同单位之间…

报错Too many open files

1、先查看系统最大打开文件数 # 查看当前系统打开文件最大数 # ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signal…

Qt 5.14.2 学习记录 —— 이십삼 绘图API

文章目录 1、概念2、API 1、概念 Qt的各个控件本质是画出来的。有时候现有控件无法完成所需功能&#xff0c;那就用绘图API来自定义控件。 QPainter提供一系列的绘图方法 QPaintDevice表示用户画的要放到哪个设备上&#xff0c;QWidget是它的子列 QPen是画笔 QBrush是画刷&…