全部一起
🌐 All together
要获取在调用 require() 时将被加载的确切文件名,可以使用 require.resolve() 函数。
🌐 To get the exact filename that will be loaded when require() is called, use
the require.resolve() function.
综合以上所有内容,这里是 require() 的高层次算法伪代码:
🌐 Putting together all of the above, here is the high-level algorithm
in pseudocode of what require() does:
require(X) 来自路径 Y 的模 1. 如果 X 是核心模块,a. 返回核心模块 b. 停止 2. 如果 X 以 '/' 开头 a. 将 Y 设置为文件系统的根目录 3. 如果 X 以 './' 或 '/' 或 '../' 开头: a. LOAD_AS_FILE(Y + X) b. LOAD_AS_DIRECTORY(Y + X) c. 抛出 "未找到" 4. 如果 X 以 '#' 开头 a. LOAD_PACKAGE_IMPORTS(X, dirname(Y)) 5. LOAD_PACKAGE_SELF(X, dirname(Y)) 6. LOAD_NODE_MODULES(X, dirname(Y)) 7. 抛出“未找到” LOAD_AS_FILE(X) 1. 如果 X 是一个文件,则按其文件扩展名格式加载 X。停止 2. 如果X.js是文件,请以JavaScript文本加载X.js。停下 3. 如果X.json是一个文件,解析X.json为JavaScript对象。停下 4. 如果 X.node 是一个文件,则将 X.node 作为二进制插件加载。停止 LOAD_INDEX(X) 1. 如果 X/index.js 是一个文件,则将 X/index.js 作为 JavaScript 文本加载。停止 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. 令 M = X + (json 的 main 字段) d. LOAD_AS_FILE(M) e. LOAD_INDEX(M) f. LOAD_INDEX(X) 已弃用 g. 抛出 "未找到" 2. LOAD_INDEX(X) LOAD_NODE_MODULES(X, START) 1. let DIRS = NODE_MODULES_PATHS(START) 2. 对于 DIRS 中的每个 DIR: a. LOAD_PACKAGE_EXPORTS(X, DIR) b. LOAD_AS_FILE(DIR/X) c. LOAD_AS_DIRECTORY(DIR/X) NODE_MODULES_PATHS(START) 1. let PARTS = path split(START) 2. let I = PARTS 的数量 - 1 3. let DIRS = [] 4. 当 I >= 0 时, a. 如果 PARTS[I] = "node_modules",继续 b. DIR = path join(PARTS[0 .. I] + "node_modules") c. DIRS = DIR + DIRS d. 令 I = I - 1 5. 返回 DIRS + GLOBAL_FOLDERS LOAD_PACKAGE_IMPORTS(X, DIR) 1. 找到最接近目录 DIR 的包作用域 SCOPE。 2. 如果未找到作用域,则返回。 3. 如果 SCOPE/package.json 中的 "imports" 为 null 或 undefined,则返回。 4. let MATCH = PACKAGE_IMPORTS_RESOLVE(X, pathToFileURL(SCOPE), ["node", "require"]) 在 ESM 解析器中定义。 5. RESOLVE_ESM_MATCH(MATCH)。 LOAD_PACKAGE_EXPORTS(X, DIR) 1. 尝试将 X 解释为 NAME 和 SUBPATH 的组合,其中名称可能有 @scope/ 前缀,子路径以斜杠开头(`/`)。 2. 如果 X 不符合该模式,或者 DIR/NAME/package.json 不是文件,则返回。 3. 解析 DIR/NAME/package.json,并查找“exports”字段。 4. 如果“exports”为 null 或未定义,则返回。 5. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(DIR/NAME), "." + SUBPATH, `package.json` "exports", ["node", "require"]) 在 ESM 解析器中定义。 6. RESOLVE_ESM_MATCH(MATCH) LOAD_PACKAGE_SELF(X, DIR) 1. 找到最接近目录 DIR 的包作用域 SCOPE。 2. 如果未找到作用域,则返回。 3. 如果 SCOPE/package.json 中的 "exports" 为 null 或 undefined,则返回。 4. 如果 SCOPE/package.json 中的 "name" 不是 X 的第一个部分,则返回。 5. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(SCOPE), "." + X.slice("name".length), `package.json` "exports", ["node", "require"]) 在 ESM 解析器中定义。 6. RESOLVE_ESM_MATCH(MATCH) RESOLVE_ESM_MATCH(MATCH) 1. let { RESOLVED, EXACT } = MATCH 2. let RESOLVED_PATH = fileURLToPath(RESOLVED) 3. 如果 EXACT 为真,a. 如果 RESOLVED_PATH 处的文件存在,则按其扩展名格式加载 RESOLVED_PATH。停止 4. 否则,如果 EXACT 为 false, a. LOAD_AS_FILE(RESOLVED_PATH) b. LOAD_AS_DIRECTORY(RESOLVED_PATH) 5. 抛出“未找到”