Rust port of enhanced-resolve.
- Released on crates.io and npm.
- Implements the ESM and CommonJS module resolution algorithm specification.
- Built-in tsconfig-paths-webpack-plugin
- support extending tsconfig defined in tsconfig.extends
- support paths alias defined in tsconfig.compilerOptions.paths
- support project references defined tsconfig.references
- support template variable ${configDir} for substitution of config files directory path
 
- support extending tsconfig defined in 
- Supports in-memory file system via the FileSystemtrait.
- Contains tracinginstrumentation.
See index.d.ts for resolveSync and ResolverFactory API.
Quick example:
import assert from 'assert';
import path from 'path';
import resolve, { ResolverFactory } from './index.js';
// `resolve`
assert(resolve.sync(process.cwd(), './index.js').path, path.join(cwd, 'index.js'));
// `ResolverFactory`
const resolver = new ResolverFactory();
assert(resolver.sync(process.cwd(), './index.js').path, path.join(cwd, 'index.js'));See https://stackblitz.com/edit/oxc-resolver for usage example.
See docs.rs/oxc_resolver.
- For node.js, yarn pnp should work without any configuration, given the following conditions:
- the program is called with the yarncommand, where the valueprocess.versions.pnpis set.
- .pnp.cjsmanifest file exists in the closest directory, searched from the current working directory,
- no multi-project setup, per second bullet point in FIND_PNP_MANIFEST
 
- the program is called with the 
An absolute path to a directory where the specifier is resolved against.
For CommonJS modules, it is the __dirname variable that contains the absolute path to the folder containing current module.
For ECMAScript modules, it is the value of import.meta.url.
Behavior is undefined when given a path to a file.
The string passed to require or import, i.e. require("specifier") or import "specifier"
- Error: Package subpath '.' is not defined by "exports" in- occurs when resolving without- conditionNames.
The following usages apply to both Rust and Node.js; the code snippets are written in JavaScript.
To handle the exports field in package.json, ESM and CJS need to be differentiated.
defaultConditions is the conditional environment name array, ["node", "import"].
This means when the caller is an ESM import (import "module"), resolve options should be
{
  "conditionNames": ["node", "import"]
}LOAD_PACKAGE_EXPORTS(X, DIR)
- let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(DIR/NAME), "." + SUBPATH,
package.json"exports", ["node", "require"]) defined in the ESM resolver.
This means when the caller is a CJS require (require("module")), resolve options should be
{
  "conditionNames": ["node", "require"]
}To support both CJS and ESM with the same cache:
const esmResolver = new ResolverFactory({
  conditionNames: ['node', 'import'],
});
const cjsResolver = esmResolver.cloneWithOptions({
  conditionNames: ['node', 'require'],
});From this non-standard spec:
The
browserfield is provided to JavaScript bundlers or component tools when packaging modules for client side use.
The option is
{
  "aliasFields": ["browser"]
}{
  "mainFields": ["module", "main"]
}Quoting esbuild's documentation:
- main- This is the standard field for all packages that are meant to be used with node. The name main is hard-coded in to node's module resolution logic itself. Because it's intended for use with node, it's reasonable to expect that the file path in this field is a CommonJS-style module.
- module- This field came from a proposal for how to integrate ECMAScript modules into node. Because of this, it's reasonable to expect that the file path in this field is an ECMAScript-style module. This proposal wasn't adopted by node (node uses "type": "module" instead) but it was adopted by major bundlers because ECMAScript-style modules lead to better tree shaking, or dead code removal.
- browser- This field came from a proposal that allows bundlers to replace node-specific files or modules with their browser-friendly versions. It lets you specify an alternate browser-specific entry point. Note that it is possible for a package to use both the browser and module field together (see the note below).
The following options are aligned with enhanced-resolve, and is implemented for Rust crate usage.
See index.d.ts for Node.js usage.
| Field | Default | Description | 
|---|---|---|
| alias | {} | A hash map of module alias configurations | 
| aliasFields | [] | A list of alias fields in description files | 
| extensionAlias | {} | An object which maps extension to extension aliases | 
| conditionNames | [] | A list of exports field condition names | 
| enforceExtension | false | Enforce that a extension from extensions must be used | 
| exportsFields | ["exports"] | A list of exports fields in description files | 
| extensions | [".js", ".json", ".node"] | A list of extensions which should be tried for files | 
| fallback | {} | Same as alias, but only used if default resolving fails | 
| fileSystem | The file system which should be used | |
| fullySpecified | false | Request passed to resolve is already fully specified and extensions or main files are not resolved for it (they are still resolved for internal requests) | 
| mainFields | ["main"] | A list of main fields in description files | 
| mainFiles | ["index"] | A list of main files in directories | 
| modules | ["node_modules"] | A list of directories to resolve modules from, can be absolute path or folder name | 
| resolveToContext | false | Resolve to a context instead of a file | 
| preferRelative | false | Prefer to resolve module requests as relative request and fallback to resolving as module | 
| preferAbsolute | false | Prefer to resolve server-relative urls as absolute paths before falling back to resolve in roots | 
| restrictions | [] | A list of resolve restrictions | 
| roots | [] | A list of root paths | 
| symlinks | true | Whether to resolve symlinks to their symlinked location | 
| allowPackageExportsInDirectoryResolve | false | Allow exportsfield inrequire('../directory'). Not part ofenhanced-resolve. | 
| Field | Default | Description | 
|---|---|---|
| tsconfig | None | TypeScript related config for resolver | 
| tsconfig.configFile | A relative path to the tsconfig file based on cwd, or an absolute path of tsconfig file. | |
| tsconfig.references | [] | - 'auto': inherits from TypeScript config - string []: relative path (based on directory of the referencing tsconfig file) or absolute path of referenced project's tsconfig | 
| Field | Default | Description | 
|---|---|---|
| descriptionFiles | ["package.json"] | A list of description files to read from | 
| cachePredicate | function() { return true }; | A function which decides whether a request should be cached or not. An object is passed to the function with pathandrequestproperties. | 
| cacheWithContext | true | If unsafe cache is enabled, includes request.contextin the cache key | 
| plugins | [] | A list of additional resolve plugins which should be applied | 
| resolver | undefined | A prepared Resolver to which the plugins are attached | 
| unsafeCache | false | Use this cache object to unsafely cache the successful requests | 
The following environment variable emits tracing information for the oxc_resolver::resolve function.
e.g.
2024-06-11T07:12:20.003537Z DEBUG oxc_resolver: options: ResolveOptions { ... }, path: "...", specifier: "...", ret: "..."
    at /path/to/oxc_resolver-1.8.1/src/lib.rs:212
    in oxc_resolver::resolve with path: "...", specifier: "..."
The input values are options, path and specifier, the returned value is ret.
OXC_LOG=DEBUG your_program
RD_LOG='oxc_resolver' rolldown buildTests are ported from
- enhanced-resolve
- tsconfig-path and parcel-resolver for tsconfig-paths
Test cases are located in ./src/tests, fixtures are located in ./tests
- alias.test.js
- browserField.test.js
- dependencies.test.js
- exportsField.test.js
- extension-alias.test.js
- extensions.test.js
- fallback.test.js
- fullSpecified.test.js
-  identifier.test.js (see unit test in crates/oxc_resolver/src/request.rs)
- importsField.test.js
- incorrect-description-file.test.js (need to add ctx.fileDependencies)
- missing.test.js
-  path.test.js (see unit test in crates/oxc_resolver/src/path.rs)
- plugins.test.js
- pnp.test.js
- resolve.test.js
- restrictions.test.js (partially done, regex is not supported yet)
- roots.test.js
- scoped-packages.test.js
- simple.test.js
- symlink.test.js
Irrelevant tests
- CachedInputFileSystem.test.js
- SyncAsyncFileSystemDecorator.test.js
- forEachBail.test.js
- getPaths.test.js
- pr-53.test.js
- unsafe-cache.test.js
- yield.test.js
oxc_resolver is free and open-source software licensed under the MIT License.
Oxc partially copies code from the following projects.
| Project | License | 
|---|---|
| webpack/enhanced-resolve | MIT | 
| dividab/tsconfig-paths | MIT | 
| parcel-bundler/parcel | MIT | 
| tmccombs/json-comments-rs | Apache 2.0 | 
