node模块查找策略

在路径 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值