feat: package map support - #1246
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1246 +/- ##
==========================================
- Coverage 93.86% 93.54% -0.33%
==========================================
Files 21 22 +1
Lines 4221 4368 +147
==========================================
+ Hits 3962 4086 +124
- Misses 259 282 +23 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Merging this PR will improve performance by 5.59%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ⚡ | pm/bun-isolated |
1.1 ms | 1 ms | +8.08% |
| ⚡ | pm/yarn-flat |
982.5 µs | 924.3 µs | +6.29% |
| ⚡ | resolver_memory[multi-thread] |
293.3 µs | 276.3 µs | +6.13% |
| ⚡ | pm/yarn-isolated |
1 ms | 1 ms | +3.8% |
| ⚡ | pm/pnpm-isolated |
1.1 ms | 1 ms | +3.7% |
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing feat/package-map-support (0faca8a) with main (82940eb)
Footnotes
-
5 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
| // 1. Determine which package performs the resolution request from the importer's path. | ||
| let Some(importer_id) = package_map.importer_package(cached_path.path()) else { | ||
| return Err(ResolveError::PackageMapExternalFile(cached_path.to_path_buf())); | ||
| }; |
There was a problem hiding this comment.
Note that this works for a first iteration but is an approximation: multiple entries from package maps are allowed to have the same path on disk, so relying on the path to get the package ID leaves room for ambiguity.
The ideal fix would be to change CachedPath to be a combination of a PackageId and a Path. It's more involved since it touches the public interface so it probably should be a separate work.
And for context, this ability to have multiple packages share the same path with different package IDs is important to unlock proper peer dependencies semantics in workspaces (ie get rid of injectWorkspacePackages).
Implements support for https://nodejs.org/docs/latest/api/packages.html#package-maps
Note: this is totally written by AI and I have not reviewed it
(tested on Windows)
1. Feature: package maps in oxc-resolver
Implemented Node.js package maps, enabled by an option taking the path to a
.package-map.json.ResolveOptions.package_map: Option<PathBuf>(+with_package_mapbuilder); newsrc/package_map.rs(parseurls relative +file:, importer/dependency lookup).require_bare: when configured, bare specifiers resolve exclusively through the map (hashmap lookup) instead of walkingnode_modules; relative/absolute/builtin unaffected.PackageMapExternalFile(ERR_PACKAGE_MAP_EXTERNAL_FILE); undeclared dependency →NotFound; no node_modules fallback. Lazy +OnceLock-memoized load via theFileSystemtrait.src/tests/package_map.rs+ unit tests; NAPI binding left unexposed (package_map: None).2. Rolldown integration
[patch.crates-io]inrolldown/Cargo.toml→ local oxc-resolver (bothoxc_resolverandoxc_resolver_napi).crates/rolldown_resolver/src/resolver_config.rs: envROLLDOWN_PACKAGE_MAP(empty disables; path enables) else auto-detectcwd/node_modules/.package-map.json.just build-rolldown-release(LTO release.node, ~2m25s).3. Benchmark setup
nodeExperimentalPackageMaplanded in v11.8.0; used pnpm 11.9.0.rolldown-benchmarksworkspace couldn't install under pnpm 11.9 (itspkg.pr.newoverrides lack integrity → rejected); configs restored to original.D:/documents/GitHub/pm-bench-10000): identicalapps/10000/src(10,002 files; ~30k bare-specifier resolves), deps declared so pnpm 11.9 generatednode_modules/.package-map.json(standardmode). Same CLI + config for both arms; onlyROLLDOWN_PACKAGE_MAPdiffers.4. Results (Rolldown build, median internal ms)
~17–18% faster rolldown builds, reproducible; interleaving rules out ordering/cache bias.
Correctness: treatment produces the correct ~9.8 MB bundle; removing
reactfrom the map makes rolldown fail withUNRESOLVED_IMPORTdespite react being on disk — proving bare specifiers route exclusively through the map.5. State / locations
rolldown-benchmarks— restored to original.pm-bench-10000— kept (re-run commands in the file).[patch.crates-io]block before committing rolldown.