Deviopath › Node.js

CommonJS require() Resolution

Hard · Modules

Implement the algorithm Node.js uses to find the file behind require(request) in CommonJS: the "All together" pseudocode from the Node docs (without the exports and imports fields of package.json).

resolveModule(files, request, fromFile): files maps absolute file paths to their contents (directories exist implicitly), and fromFile is the absolute path of the module calling require. Return the absolute path of the resolved file, or throw.

- Core modules: if request is in CORE_MODULES (given in the starter), return "node:" + request, even if a package with that name exists. A request starting with node: returns itself if the rest is a core module; otherwise throw code: "ERR_UNKNOWN_BUILTIN_MODULE" with message "No such built-in module: <request>" (this is what require() throws; require.resolve() reports it as MODULE_NOT_FOUND).

- Paths (starting with ./, ../ or /): resolve against the directory of fromFile (or the root for /), handling . and ... Then try LOAD_AS_FILE, then LOAD_AS_DIRECTORY.

- LOAD_AS_FILE(X): the first existing file of X, X.js, X.json, X.node.

- LOAD_INDEX(X): the first existing file of X/index.js, X/index.json, X/index.node.

- LOAD_AS_DIRECTORY(X): if X/package.json exists and its "main" is truthy, let M be X joined with main, and try LOAD_AS_FILE(M), then LOAD_INDEX(M), then LOAD_INDEX(X) (a deprecated fallback that Node still supports). If all fail, throw "not found" immediately (do not keep searching elsewhere). Without a usable main, use LOAD_INDEX(X).

- Bare names (lodash, lodash/fp, @scope/tool): look in node_modules directories, starting at the directory of fromFile and moving up to /node_modules. Skip ancestors that are themselves called node_modules (there is never a node_modules/node_modules). In each DIR, try LOAD_AS_FILE(DIR/request), then LOAD_AS_DIRECTORY(DIR/request).

- Otherwise throw code: "MODULE_NOT_FOUND" with message "Cannot find module '<request>'". (Real Node appends a "Require stack" to this message, and words the broken-main case differently. Here, keep the short form.)

The driver resolveAll(files, fromFile, requests) is already written. It returns the resolved path, or "<code>: <message>", for each request.

Next: Express-Like Middleware Engine