Skip to content

[node-resolve] Replace resolve and some rollup-baked exports fields handling with a Rust-based resolver #1874

Open

Description

@SukkaW
  • Rollup Plugin Name: @rollup/plugin-node-resolve
  • Rollup Plugin Version: 16.0.1

Feature Use Case

Currently, @rollup/plugin-node-resolve relies on resolve, a resolver created and maintained by Browserify, which hasn't been actively maintained and lacks the export map feature.

Rollup builds @rollup/plugin-node-resolve on top of resolve with extra code to handle the browser field and export map.

The resolve plugin is a hot path during the build process, ranging from 10 to thousands or even more. Rustifying the resolver could benefit performance.

Feature Proposal

Maybe Rollup could rustify the resolve part, starting with @rollup/plugin-node-resolve. It is possible to use a Rust-based resolver, like oxc-resolver or rspack-resolver directly. Rollup could also build a rollup-flavored one on top of those crates.

Also, those resolvers already support features (that resolve doesn't have) like export map and the browser field, so @rollup/plugin-node-resolve wouldn't need to re-implement those features again.

After experimenting with @rollup/plugin-node-resolve, we could then decide whether the Rollup core's built-in resolver can benefit from rustify as well.

Activity

  1. lukastaegert commented on Jun 1, 2025

    @lukastaegert
    Member

    I am not sure if it definitely needs to be "Rust" to improve performance, but I agree that completely owning the resolver will bring benefits. The greatest benefits I actually see from caching all directory accesses etc. during each build, something that currently is only done in the part handled by the old resolve plugin but not by the new parts.
    But sure, it can also be Rust as long as jump between JavaScript and Rust does not become another bottleneck.
    Unfortunately, I had little resources to pursue anything here, but I would be open if someone else picked it up.

  2. SukkaW commented on Jun 1, 2025

    @SukkaW
    ContributorAuthor

    The greatest benefits I actually see from caching all directory accesses etc. during each build

    I see benefits from native exports and browser features, which are currently still maintained by rollup (which only adds burdens).

    But sure, it can also be Rust as long as jump between JavaScript and Rust does not become another bottleneck.

    webpack's enhanced-resolve could be the JavaScript alternative and is battle-tested. Also supports exports and browser by default.

  3. JounQin commented on Jun 10, 2025

    @JounQin
    Contributor
  4. SukkaW commented on Jun 10, 2025

    @SukkaW
    ContributorAuthor

    @lukastaegert Just FYI, resolve has been replaced by https://github.com/unrs/unrs-resolver#readme in Jest 30: https://jestjs.io/blog#performance--memory-improvements

    unrs-resolver doesn't support options of @rollup/plugin-node-resolver, and supporting those options will affect performance. So the Jest case doesn't make any points here.

  5. JounQin commented on Jun 10, 2025

    @JounQin
    Contributor

    Then oxc-resolver and @rspack/resolver are even worse, LOL.

  6. james-pre commented on Jul 2, 2026

    @james-pre

    Why not use import.meta.resolve?

  7. SukkaW commented on Jul 2, 2026

    @SukkaW
    ContributorAuthor

    Why not use import.meta.resolve?

    Because to avoid breaking changes, rollup/plugin-node-resolve still needs to support the CommonJS resolve algorithm.

  8. james-pre commented on Jul 3, 2026

    @james-pre

    I took a look at all of resolve's dependencies:

    • es-errors (replaceable with builtins)
    • is-core-module (can be replaced with native isBuiltin)
      • hasown (replaceable with Object.hasOwn)
        • function-bind (replaceable with function.prototype.bind)
    • path-parse (replaceable with path.parse)
    • supports-preserve-symlinks-flag

    One maintainer (ljharb) maintains all of these except path-parse, and has demonstrated an unwillingness to clean up dependencies despite native replacements existing, claiming security*. resolve uses about 50 TB of bandwidth weekly.

    * In an issue on is-core-module:

    Technically it’s Object.prototype.hasOwnProperty.call, and that relies on both Object.prototype and Function.prototype being unmodified.

    Using hasown ensures that later mutation of builtins doesn’t break things, so it’ll be relevant and necessary and beneficial forever.

    • Mutation can occur before importing this one
    • This is not the job of the package, this is the responsibility of the JS host (shout out to --frozen-intrinsics)
    • const hasOwn = Object.hasOwn is a one line replacement for the 41.8 kB from hasown + its dependencies
    • There is zero need to polyfill function.prototype.bind, it has existed on every JS host for the past 15 years
  9. SukkaW commented on Jul 3, 2026

    @SukkaW
    ContributorAuthor

    @james-pre ljharb polyfill issue is not a concern here. My concern is that, currently rollup/plugin-node-resolve implements its own exports map resolution, where we may use other battle-tested resolving libraries, like enhanced-resolve or oxc-resolve to avoid re-inventing wheels.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions