全部一起
【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:】
从路径 Y 的模块中加载 X 1. 如果 X 是核心模块, a. 返回核心模块 b. 停止 2. 如果 X 以 '/' 开头, a. 将 Y 设置为文件系统根目录 3. 如果 X 以 './'、'/' 或 '../' 开头, a. 以文件方式加载(Y + X) b. 以目录方式加载(Y + X) c. 抛出“未找到”异常 4. 如果 X 以 '#' 开头, a. 加载包导入(X, dirname(Y)) 5. 加载包自身(X, dirname(Y)) 6. 加载 Node 模块(X, dirname(Y)) 7. 抛出“未找到”异常 LOAD_AS_FILE(X) 1. 如果 X 是一个文件,则按其文件扩展名格式加载 X。停止 2. 如果 X.js 是一个文件,则将 X.js 作为 JavaScript 文本加载。停止 3. 如果 X.json 是一个文件,则将 X.json 解析为 JavaScript 对象。停止 4. 如果 X.node 是一个文件,则将 X.node 作为二进制插件加载。停止 【LOAD_AS_FILE(X) 1. If X is a file, load X as its file extension format. STOP 2. If X.js is a file, load X.js as JavaScript text. STOP 3. If X.json is a file, parse X.json to a JavaScript Object. STOP 4. If X.node is a file, load X.node as binary addon. STOP】 加载索引(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_INDEX(X) 1. If X/index.js is a file, load X/index.js as JavaScript text. STOP 2. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP 3. If X/index.node is a file, load X/index.node as binary addon. STOP】 LOAD_AS_DIRECTORY(X) 1. 如果 X/package.json 是一个文件, a. 解析 X/package.json,并查找 "main" 字段。 b. 如果 "main" 是假值,跳转到 2。 c. 令 M = X +(json 中的 main 字段) d. 以文件方式加载 M(LOAD_AS_FILE(M)) e. 加载 index(M)(LOAD_INDEX(M)) f. 加载 index(X)(LOAD_INDEX(X) 已弃用) g. 抛出 "未找到"(THROW "not found") 2. 加载 index(X)(LOAD_INDEX(X)) 【LOAD_AS_DIRECTORY(X) 1. If X/package.json is a file, a. Parse X/package.json, and look for "main" field. b. If "main" is a falsy value, GOTO 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)】 加载节点模块(X, START) 1. 让 DIRS = 节点模块路径(START) 2. 对于 DIRS 中的每个 DIR: a. 加载包导出(X, DIR) b. 作为文件加载(DIR/X) c. 作为目录加载(DIR/X) 【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)】 NODE_MODULES_PATHS(START) 1. 设 PARTS = path split(START) 2. 设 I = PARTS 的数量 - 1 3. 设 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 【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】 LOAD_PACKAGE_IMPORTS(X, DIR) 1. 找到距离 DIR 最近的包作用域 SCOPE。 2. 如果未找到作用域,则返回。 3. 如果 SCOPE/package.json 中的“imports”为 null 或 undefined,则返回。 4. 令 MATCH = PACKAGE_IMPORTS_RESOLVE(X, pathToFileURL(SCOPE), ["node", "require"]) 在 ESM 解析器中定义。 5. RESOLVE_ESM_MATCH(MATCH). LOAD_PACKAGE_EXPORTS(X, DIR) 1. 尝试将 X 解释为 NAME 和 SUBPATH 的组合,其中 NAME 可能带有 @scope/ 前缀,SUBPATH 以斜杠 (`/`) 开头。 2. 如果 X 不符合此模式或者 DIR/NAME/package.json 不是文件,则返回。 3. 解析 DIR/NAME/package.json,并查找 "exports" 字段。 4. 如果 "exports" 为 null 或 undefined,则返回。 5. 让 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. 令 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. 让 { RESOLVED, EXACT } = MATCH 2. 让 RESOLVED_PATH = fileURLToPath(RESOLVED) 3. 如果 EXACT 为真, a. 如果 RESOLVED_PATH 处的文件存在,按其扩展名格式加载 RESOLVED_PATH。停止 4. 否则,如果 EXACT 为假, a. LOAD_AS_FILE(RESOLVED_PATH) b. LOAD_AS_DIRECTORY(RESOLVED_PATH) 5. 抛出 “未找到”