All together
History
Introduced in: v0.10.0
v0.10.0
To get the exact filename that will be loaded when require() is called, use
the require.resolve() function.
Putting together all of the above, here is the high-level algorithm
in pseudocode of what require() does:
require(X) from module at path Y 1. If X is a core module, a. return the core module b. STOP 2. If X begins with '/' a. set Y to the file system root 3. If X is equal to '.', or X begins with './', '/' or '../' a. LOAD_AS_FILE(Y + X) b. LOAD_AS_DIRECTORY(Y + X) c. THROW "not found" 4. If X begins with '#' a. LOAD_PACKAGE_IMPORTS(X, dirname(Y)) 5. LOAD_PACKAGE_SELF(X, dirname(Y)) 6. If a package map PACKAGE_MAP exists, a. Find the package ID for the package owning Y 1. Let PARENT_PACKAGE_ID be FIND_PACKAGE_ID(dirname(Y), PACKAGE_MAP) b. LOAD_PACKAGE_MAP(X, PARENT_PACKAGE_ID, PACKAGE_MAP) 7. LOAD_NODE_MODULES(X, dirname(Y)) 8. THROW "not found" MAYBE_DETECT_AND_LOAD(X) 1. If X parses as a CommonJS module, load X as a CommonJS module. STOP. 2. Else, if the source code of X can be parsed as ECMAScript module using DETECT_MODULE_SYNTAX defined in the ESM resolver, a. Load X as an ECMAScript module. STOP. 3. THROW the SyntaxError from attempting to parse X as CommonJS in 1. STOP. 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, a. Find the closest package scope SCOPE to X. b. If no scope was found 1. MAYBE_DETECT_AND_LOAD(X.js) c. If the SCOPE/package.json contains "type" field, 1. If the "type" field is "module", load X.js as an ECMAScript module. STOP. 2. If the "type" field is "commonjs", load X.js as a CommonJS module. STOP. d. MAYBE_DETECT_AND_LOAD(X.js) 3. If X.json is a file, load X.json to a JavaScript Object. STOP 4. If X.node is a file, load X.node as binary addon. STOP LOAD_INDEX(X) 1. If X/index.js is a file a. Find the closest package scope SCOPE to X. b. If no scope was found, load X/index.js as a CommonJS module. STOP. c. If the SCOPE/package.json contains "type" field, 1. If the "type" field is "module", load X/index.js as an ECMAScript module. STOP. 2. Else, load X/index.js as a CommonJS module. 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. 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) LOAD_NODE_MODULES(X, START) 1. Try to interpret X as a combination of NAME and SUBPATH where the name may have a @scope/ prefix and the subpath begins with a slash (`/`). 2. let DIRS = NODE_MODULES_PATHS(START) 3. for each DIR in DIRS: a. LOAD_PACKAGE_EXPORTS(SUBPATH, DIR/NAME) 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 = count of PARTS - 1 3. let DIRS = [] 4. while I >= 0, a. if PARTS[I] = "node_modules", GOTO d. b. DIR = path join(PARTS[0 .. I] + "node_modules") c. DIRS = DIRS + DIR d. let I = I - 1 5. return DIRS + GLOBAL_FOLDERS FIND_PACKAGE_ID(PATH, PACKAGE_MAP) 1. Find the PACKAGE_ID for the entry whose "path" is a parent directory of PATH 2. If multiple entries are found, THROW "ambiguous resolution" 3. If no entry was found, THROW "external file". 4. return PACKAGE_ID LOAD_PACKAGE_MAP(X, PARENT_PACKAGE_ID, PACKAGE_MAP) 1. Try to interpret X as a combination of NAME and SUBPATH where the name may have a @scope/ prefix and the subpath begins with a slash (`/`). 2. Find the package map entry for key PARENT_PACKAGE_ID 3. Look up NAME in the entry's "dependencies" map. 4. If NAME is not found, THROW "not found". 5. Let TARGET be PACKAGE_MAP.packages[dependencies[name]] 6. Let PACKAGE_PATH be the resolved path of TARGET. 7. LOAD_PACKAGE_EXPORTS(SUBPATH, PACKAGE_PATH) 8. LOAD_AS_FILE(PACKAGE_PATH/SUBPATH) 9. LOAD_AS_DIRECTORY(PACKAGE_PATH/SUBPATH) 10. THROW "not found" LOAD_PACKAGE_IMPORTS(X, DIR) 1. Find the closest package scope SCOPE to DIR. 2. If no scope was found, return. 3. If the SCOPE/package.json "imports" is null or undefined, return. 4. If `--no-require-module` is not enabled a. let CONDITIONS = ["node", "require", "module-sync"] b. Else, let CONDITIONS = ["node", "require"] 5. let MATCH = PACKAGE_IMPORTS_RESOLVE(X, pathToFileURL(SCOPE), CONDITIONS) defined in the ESM resolver. 6. RESOLVE_ESM_MATCH(MATCH). LOAD_PACKAGE_EXPORTS(SUBPATH, PACKAGE_DIR) 1. Parse PACKAGE_DIR/package.json, and look for "exports" field. 2. If "exports" is null or undefined, return. 3. If `--no-require-module` is not enabled a. let CONDITIONS = ["node", "require", "module-sync"] b. Else, let CONDITIONS = ["node", "require"] 4. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(PACKAGE_DIR), "." + SUBPATH, `package.json` "exports", CONDITIONS) defined in the ESM resolver. 5. RESOLVE_ESM_MATCH(MATCH) LOAD_PACKAGE_SELF(X, DIR) 1. Find the closest package scope SCOPE to DIR. 2. If no scope was found, return. 3. If the SCOPE/package.json "exports" is null or undefined, return. 4. If the SCOPE/package.json "name" is not the first segment of X, return. 5. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(SCOPE), "." + X.slice("name".length), `package.json` "exports", ["node", "require"]) defined in the ESM resolver. 6. RESOLVE_ESM_MATCH(MATCH) RESOLVE_ESM_MATCH(MATCH) 1. let RESOLVED_PATH = fileURLToPath(MATCH) 2. If the file at RESOLVED_PATH exists, load RESOLVED_PATH as its extension format. STOP 3. THROW "not found"
The "ESM resolver" is defined in the ESM documentation.