Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

unrs-resolver

unrs16.8mMIT1.8.0TypeScript support: included

UnRS Resolver Node API with PNP support

readme

[!NOTE]

This is a fork of oxc-resolver and rspack-resolver, and will be used in eslint-plugin-import-x and eslint-import-resolver-typescript cause 100% compatible with enhanced-resolve is the non-goal of oxc-resolver itself, we add enhanced-resolve specific features like pnp support.

We also fix several bugs reported by eslint-plugin-import-x and eslint-import-resolver-typescript users:

The list could be longer in the future, but we don't want to make it too long here.

We also sync with oxc-resolver and rspack-resolver regularly to keep up with the latest changes:

Last but not least, we prepare some bug fix PRs first on our side and PR back into upstream projects, and we will keep doing this in the future:

Crates.io npmjs.com

Docs.rs Build Status Code Coverage CodSpeed Badge Sponsors MIT licensed

UnRS Resolver

Rust port of enhanced-resolve.

Usage

npm package

See index.d.ts for resolveSync and ResolverFactory API.

Quick example:

import assert from 'node:assert';
import path from 'node:path';

import resolve, { ResolverFactory } from 'unrs-resolver';

// `resolve`
assert(resolve.sync(process.cwd(), './index.js').path, path.resolve('index.js'));

// `ResolverFactory`
const resolver = new ResolverFactory();
assert(resolver.sync(process.cwd(), './index.js').path, path.resolve('index.js'));

Rust

See docs.rs/unrs_resolver.

Terminology

directory

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.

specifier

The string passed to require or import, i.e. require("specifier") or import "specifier"

Errors and Trouble Shooting

  • Error: Package subpath '.' is not defined by "exports" in - occurs when resolving without conditionNames.

Configuration

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.

ESM

Per ESM Resolution algorithm

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"]
}

CJS

Per CJS Resolution algorithm

LOAD_PACKAGE_EXPORTS(X, DIR)

  1. 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"]
}

Cache

To support both CJS and ESM with the same cache:

const esmResolver = new ResolverFactory({
  conditionNames: ['node', 'import'],
});

const cjsResolver = esmResolver.cloneWithOptions({
  conditionNames: ['node', 'require'],
});

Browser Field

From this non-standard spec:

The browser field is provided to JavaScript bundlers or component tools when packaging modules for client side use.

The option is

{
  "aliasFields": ["browser"]
}

Main Field

{
  "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).

Options

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 list of module alias configurations or an object which maps key to value
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
descriptionFiles ["package.json"] A list of description files to read from
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, if possible.

Unimplemented Options

Field Default Description
cachePredicate function() { return true }; A function which decides whether a request should be cached or not. An object is passed to the function with path and request properties.
cacheWithContext true If unsafe cache is enabled, includes request.context in 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

Debugging

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.

NAPI

OXC_LOG=DEBUG your_program

Rolldown

RD_LOG='oxc_resolver' rolldown build

Test

Tests are ported from

Test cases are located in ./src/tests, fixtures are located in ./tests

  • <input checked="" disabled="" type="checkbox"> alias.test.js
  • <input checked="" disabled="" type="checkbox"> browserField.test.js
  • <input checked="" disabled="" type="checkbox"> dependencies.test.js
  • <input checked="" disabled="" type="checkbox"> exportsField.test.js
  • <input checked="" disabled="" type="checkbox"> extension-alias.test.js
  • <input checked="" disabled="" type="checkbox"> extensions.test.js
  • <input checked="" disabled="" type="checkbox"> fallback.test.js
  • <input checked="" disabled="" type="checkbox"> fullSpecified.test.js
  • <input checked="" disabled="" type="checkbox"> identifier.test.js (see unit test in crates/oxc_resolver/src/request.rs)
  • <input checked="" disabled="" type="checkbox"> importsField.test.js
  • <input checked="" disabled="" type="checkbox"> incorrect-description-file.test.js (need to add ctx.fileDependencies)
  • <input checked="" disabled="" type="checkbox"> missing.test.js
  • <input checked="" disabled="" type="checkbox"> path.test.js (see unit test in crates/oxc_resolver/src/path.rs)
  • <input disabled="" type="checkbox"> plugins.test.js
  • <input disabled="" type="checkbox"> pnp.test.js
  • <input checked="" disabled="" type="checkbox"> resolve.test.js
  • <input checked="" disabled="" type="checkbox"> restrictions.test.js (partially done, regex is not supported yet)
  • <input checked="" disabled="" type="checkbox"> roots.test.js
  • <input checked="" disabled="" type="checkbox"> scoped-packages.test.js
  • <input checked="" disabled="" type="checkbox"> simple.test.js
  • <input checked="" disabled="" type="checkbox"> 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

Sponsors

Sponsors

1stG UnRs UnTS
1stG Open Collective backers and sponsors UnRs Open Collective backers and sponsors UnTS Open Collective backers and sponsors

Backers

1stG UnRs UnTS
1stG Open Collective backers and sponsors UnRs Open Collective backers and sponsors UnTS Open Collective backers and sponsors

📖 License

unrs_resolver is free and open-source software licensed under the MIT License.

UnRS 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
oxc-project/oxc-resolver MIT
web-infra-dev/rspack-resolver MIT

changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

1.8.0 - 2025-06-11

Features

  • support runtime fallback for webcontainer (#144) (by @JounQin) - #144
  • merge from upstream oxc-project/oxc-resolver - 6th (#146) (by @JounQin) - #146

Chore

  • (deps) update all dependencies (#141) (by @renovate[bot])

Contributors

  • @JounQin
  • @renovate[bot]

1.7.13 - 2025-06-10

Bug Fixes

  • support extends in referenced project (#142)

1.7.12 - 2025-06-09

Bug Fixes

  • npm protocol alias with pnp should be supported (#139)

1.7.11 - 2025-06-05

Bug Fixes

  • remove invalid file cache due to extension alias (#136)

1.7.10 - 2025-06-05

Bug Fixes

  • Revert "fix: custom condition_names should take higher priority than target in package.json (#115)" (#131)

Other

  • chore: bump napi v3.0.0-beta.7 (#133)

1.7.9 - 2025-06-03

Bug Fixes

1.7.8 - 2025-05-29

Bug Fixes

  • resolve symlink with nested node_modules (#125)

1.7.7 - 2025-05-29

Bug Fixes

  • resolve dir index with dot specifier correctly (#123)

1.7.6 - 2025-05-28

Bug Fixes

  • prefer index over current file for . and ./ (#121)

1.7.5 - 2025-05-28

Bug Fixes

  • should try package exports first per spec (#118)

1.7.4 - 2025-05-28

Bug Fixes

  • prefer file over package dir in node_modules (#116)

1.7.3 - 2025-05-28

Bug Fixes

  • custom condition_names should take higher priority than target in package.json (#115)

1.7.2 - 2025-04-27

Bug Fixes

  • bump napi-postinstall to fix yarn pnp compatibility issue (#106)

1.7.1 - 2025-04-26

Chore

  • bump napi-postinstall to support yarn/pnpm on webcontainer (#103)

Testing

  • add case for #65 (#100)

1.7.0 - 2025-04-24

Features

  • enable no_opt_arch flag for mimalloc-safe on linux-aarch64 (#98)

1.6.6 - 2025-04-23

Features

  • add new target riscv64gc-unknown-linux-musl (#96)

1.6.5 - 2025-04-23

Bug Fixes

  • rework on handling DOS device paths on Windows (#84)
  • handle package.json and tsconfig.json with BOM (#463)

Performance

  • avoid double call to parse_package_specifier (#465)

Documentation

  • add more details about the changes in this fork (#92)

1.6.4 - 2025-04-22

Bug Fixes

  • properly handle DOS device paths in strip_windows_prefix (#455)

1.6.3 - 2025-04-21

Bug Fixes

  • support load_as_directory for pnp mode (#75)

Testing

  • add case for import-js/eslint-import-resolver-typescript#429 (#76)

1.6.2 - 2025-04-21

Bug Fixes

  • resolve parent base url correctly by normalizing as absolute path (#72)

1.6.1 - 2025-04-20

Bug Fixes

  • disable mimalloc on linux with aarch64 (#69)

1.6.0 - 2025-04-20

Features

  • deserialize preserve_value_imports and imports_not_used_as_values from compilerOptions (#457)
  • deserialize target from compilerOptions (#456)

Bug Fixes

  • add napi-postinstall dep for workaround npm's bug (#66)

1.5.0 - 2025-04-11

Bug Fixes

  • resolve ${configDir} in tsconfig compilerOptions.baseUrl (#450)

1.4.1 - 2025-04-07

Refactor

  • remove unnecessary checks for query (#53)

1.4.0 - 2025-04-06

Features

  • handle query and fragment in pacakge.json exports and imports field (#443)
  • resolve emitDecoratorMetadata in tsconfig (#439)
  • (napi) add mimalloc (#423)
  • [breaking] Rust Edition 2024 (#402)
  • deserialize verbatim_module_syntax from compilerOptions (#411)
  • support wildcard * in alias plugin (#388)
  • merge options from extends tsconfig.json (#375)
  • add more fields in tsconfig#CompilerOptionsSerde (#374)
  • [breaking] generic fs cache type Resolver = ResolverGeneric<FsCache<FileSystemOs>> (#358)
  • [breaking] replace FileSystem::canonicalize with FileSystem::read_link (#331)
  • faster and stable path hash for the cache (#328)
  • add Resolver::resolve_tsconfig API (#312)
  • [breaking] add ResolveError::Builtin::prefixed_with_node_colon (#272)
  • [breaking] mark ResolveError #[non_exhaustive] (#252)
  • show tried extension aliases in ResolveError::ExtensionAlias (#251)
  • give a specific error for matched alias not found (#238)
  • Yarn PnP (#217)

Bug Fixes

  • handle query and fragment in package.json exports and imports field (#443)
  • fix bench
  • try browsers field and alias before resolving directory in node_modules (#349)
  • special case for aliasing @/ (#348)
  • normalize resolved result on Windows for root (#345)
  • don't panic when resolving / with roots (#310)
  • use same UNC path normalization logic with libuv (#306)
  • use fs::canonicalize to cover symlink edge cases (#284)
  • extensionAlias cannot resolve mathjs (#273)
  • resolve module ipaddr.js correctly when extensionAlias is provided (#228)
  • (napi) update buggy NAPI-RS versions (#225)
  • remove #[cfg(target_os = "windows")] logic in canonicalize (#221)

Performance

  • use papaya instead of dashmap (#356)
  • try directory first in node_modules (#340)
  • guard load_alias on hot path (#339)
  • use as_os_str for Hash and PartialEq operations (#338)
  • reduce hash while resolving package.json (#319)
  • reduce memory allocation while normalizing package path (#318)
  • reduce memory allocation while resolving package.json (#317)
  • use path.as_os_str().hash() instead of path.hash() (#316)
  • reduce memory allocation by using a thread_local path for path methods (#315)
  • bring back the symlink optimization (#298)
  • use simdutf8 to validate UTF-8 when reading files (#237)
  • use custom canonicalize impl to avoid useless syscall (#220)

Documentation

  • fix an incorrect comment on Context::missing_dependencies
  • mention extension must start with a . in with_extension (#313)
  • (README) should be new ResolverFactory

Refactor

  • remove papaya .collector(seize::Collector::new()) call (#393)
  • replace UnsafeCell with RefCell (#346)
  • run clippy with --all-targets (#333)
  • apply latest cargo +nightly fmt (#281)
  • add more clippy fixes (#279)
  • clean up elided lifetimes (#277)

Testing

  • fix warning on Windows
  • fix symlink test init on Windows (#307)

1.3.3 - 2025-03-29

Build

  • build: remove --strip flag (#44)

Testing

  • add nested package json case (#40)

1.3.2 - 2025-03-26

Bug Fixes

  • absolute path aliasing should not be skipped (#37)

1.3.1 - 2025-03-26

Other

  • bump all (dev) deps (#34)

1.3.0 - 2025-03-26

Features

  • enable more targets (#29 and #32)

1.2.2 - 2025-03-19

Bug Fixes

  • (pnp) support pnpapi core module and package deep link (#24)

1.2.0 - 2025-03-18

Features

  • (napi) add mimalloc (#423) (#18)
  • merge from upstream oxc-project/oxc-resolver (#15)

1.1.2 - 2025-03-16

Fixed

  • references should take higher priority (#13)
  • takes paths and references into account at the same time
  • should always try resolve_path_alias

1.1.1 - 2025-03-16

Other

  • bump all (dev) deps
  • bump to edition 2024

1.1.0 - 2025-03-15

Added

  • support resolving path with extra query (#7)

1.0.0 - 2025-03-15

Old Changelog for oxc-resolver

CHANGELOG_OLD