Skip to content

perf: optimize ESM linking passes#14758

Merged
JSerFeng merged 1 commit into
mainfrom
perf/esm-linking
Jul 14, 2026
Merged

perf: optimize ESM linking passes#14758
JSerFeng merged 1 commit into
mainfrom
perf/esm-linking

Conversation

@JSerFeng

@JSerFeng JSerFeng commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • remove an unused per-module output-path resolution pass before ESM module analysis
  • process namespace-object propagation as an insertion-ordered worklist without cloning the full set each round
  • borrow hoisted module sets during link traversal instead of cloning them

Why

ESM linking performed async output-path resolution once per module and discarded every result. This added serial work on a high-cardinality structure before the parallel module analysis phase. Namespace propagation and hoisted-module traversal also cloned collections that can grow with the module graph.

The new flow preserves linking order and emitted output while removing those repeated computations and allocations.

Checks

  • pnpm run build:cli:dev
  • pnpm exec rstest EsmOutput.test.js (456 passed)
  • cargo clippy -p rspack_plugin_esm_library --all-targets --all-features
  • cargo fmt --all --check
  • git diff --check
  • pnpm run test:unit (9 host-contention timeout flakes; every timed-out case passed on isolated rerun)

@github-actions

github-actions Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

📝 Benchmark detail: Open

Name Base (cd0781d) Current Change
10000_big_production-mode_disable-minimize + exec 12.1 s ± 249 ms 12 s ± 265 ms -0.47 %
10000_development-mode + exec 918 ms ± 102 ms 878 ms ± 33 ms -4.36 %
10000_development-mode_hmr + stats 158 ms ± 5.4 ms 155 ms ± 16 ms -1.99 %
10000_development-mode_noop-loader + exec 1.75 s ± 23 ms 1.72 s ± 25 ms -1.50 %
10000_production-mode + exec 1.03 s ± 61 ms 991 ms ± 15 ms -4.08 %
10000_production-mode_persistent-cold + exec 1.19 s ± 44 ms 1.15 s ± 20 ms -3.40 %
10000_production-mode_persistent-hot + exec 642 ms ± 14 ms 614 ms ± 15 ms -4.42 %
10000_production-mode_source-map + exec 1.19 s ± 28 ms 1.14 s ± 56 ms -4.06 %
arco-pro_development-mode + exec 1.28 s ± 85 ms 1.23 s ± 19 ms -4.14 %
arco-pro_development-mode_hmr + stats 33 ms ± 0.72 ms 33 ms ± 5.8 ms +0.71 %
arco-pro_production-mode + exec 2.36 s ± 128 ms 2.31 s ± 61 ms -1.88 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 2.38 s ± 122 ms 2.35 s ± 94 ms -1.23 %
arco-pro_production-mode_persistent-cold + exec 2.42 s ± 103 ms 2.38 s ± 78 ms -1.67 %
arco-pro_production-mode_persistent-hot + exec 349 ms ± 6.5 ms 340 ms ± 8.7 ms -2.58 %
arco-pro_production-mode_source-map + exec 2.82 s ± 108 ms 2.75 s ± 108 ms -2.36 %
arco-pro_production-mode_source-map_persistent-cold + exec 2.9 s ± 83 ms 2.86 s ± 152 ms -1.25 %
arco-pro_production-mode_source-map_persistent-hot + exec 486 ms ± 9.9 ms 467 ms ± 10 ms -3.91 %
arco-pro_production-mode_traverse-chunk-modules + exec 2.37 s ± 84 ms 2.31 s ± 104 ms -2.58 %
bundled-threejs_development-mode + exec 183 ms ± 3.1 ms 176 ms ± 2.5 ms -3.61 %
bundled-threejs_production-mode + exec 211 ms ± 4 ms 207 ms ± 8.7 ms -1.61 %
large-dyn-imports_development-mode + exec 1.17 s ± 28 ms 1.15 s ± 25 ms -1.70 %
large-dyn-imports_production-mode + exec 1.27 s ± 15 ms 1.24 s ± 42 ms -2.94 %
threejs_development-mode_10x + exec 781 ms ± 30 ms 770 ms ± 31 ms -1.41 %
threejs_development-mode_10x_hmr + stats 115 ms ± 11 ms 107 ms ± 7.1 ms -6.95 %
threejs_production-mode_10x + exec 2.83 s ± 36 ms 2.75 s ± 49 ms -2.63 %
threejs_production-mode_10x_persistent-cold + exec 2.95 s ± 18 ms 2.9 s ± 54 ms -1.88 %
threejs_production-mode_10x_persistent-hot + exec 382 ms ± 10 ms 377 ms ± 11 ms -1.36 %
threejs_production-mode_10x_source-map + exec 3.64 s ± 74 ms 3.55 s ± 58 ms -2.57 %
10000_big_production-mode_disable-minimize + rss memory 2196 MiB ± 26.8 MiB 2186 MiB ± 21.5 MiB -0.42 %
10000_development-mode + rss memory 543 MiB ± 12.3 MiB 537 MiB ± 6.25 MiB -1.04 %
10000_development-mode_hmr + rss memory 789 MiB ± 21.8 MiB 771 MiB ± 32.7 MiB -2.27 %
10000_development-mode_noop-loader + rss memory 805 MiB ± 4.36 MiB 808 MiB ± 8.03 MiB +0.31 %
10000_production-mode + rss memory 469 MiB ± 10.6 MiB 463 MiB ± 10.9 MiB -1.28 %
10000_production-mode_persistent-cold + rss memory 669 MiB ± 9.86 MiB 664 MiB ± 11.7 MiB -0.67 %
10000_production-mode_persistent-hot + rss memory 653 MiB ± 36.6 MiB 646 MiB ± 40.9 MiB -1.14 %
10000_production-mode_source-map + rss memory 476 MiB ± 17.6 MiB 489 MiB ± 54.3 MiB +2.60 %
arco-pro_development-mode + rss memory 405 MiB ± 2.3 MiB 400 MiB ± 3.23 MiB -1.20 %
arco-pro_development-mode_hmr + rss memory 428 MiB ± 7.78 MiB 427 MiB ± 14.8 MiB -0.27 %
arco-pro_production-mode + rss memory 580 MiB ± 3.49 MiB 576 MiB ± 5.97 MiB -0.70 %
arco-pro_production-mode_generate-package-json-webpack-plugin + rss memory 593 MiB ± 10 MiB 581 MiB ± 61.3 MiB -2.17 %
arco-pro_production-mode_persistent-cold + rss memory 562 MiB ± 51.5 MiB 547 MiB ± 14.3 MiB -2.73 %
arco-pro_production-mode_persistent-hot + rss memory 292 MiB ± 11.1 MiB 292 MiB ± 5.33 MiB +0.02 %
arco-pro_production-mode_source-map + rss memory 679 MiB ± 21.9 MiB 682 MiB ± 12.6 MiB +0.47 %
arco-pro_production-mode_source-map_persistent-cold + rss memory 791 MiB ± 14.5 MiB 789 MiB ± 10.7 MiB -0.27 %
arco-pro_production-mode_source-map_persistent-hot + rss memory 422 MiB ± 16.4 MiB 416 MiB ± 9.87 MiB -1.35 %
arco-pro_production-mode_traverse-chunk-modules + rss memory 583 MiB ± 7.92 MiB 582 MiB ± 17.2 MiB -0.19 %
bundled-threejs_development-mode + rss memory 129 MiB ± 7.5 MiB 124 MiB ± 7.43 MiB -4.36 %
bundled-threejs_production-mode + rss memory 142 MiB ± 4.52 MiB 138 MiB ± 2.49 MiB -3.14 %
large-dyn-imports_development-mode + rss memory 556 MiB ± 9.53 MiB 553 MiB ± 16.2 MiB -0.41 %
large-dyn-imports_production-mode + rss memory 408 MiB ± 3.88 MiB 403 MiB ± 5.74 MiB -1.32 %
threejs_development-mode_10x + rss memory 437 MiB ± 8.71 MiB 434 MiB ± 7.19 MiB -0.84 %
threejs_development-mode_10x_hmr + rss memory 596 MiB ± 9.47 MiB 596 MiB ± 22.4 MiB -0.04 %
threejs_production-mode_10x + rss memory 616 MiB ± 20.3 MiB 620 MiB ± 11.9 MiB +0.60 %
threejs_production-mode_10x_persistent-cold + rss memory 576 MiB ± 4.53 MiB 575 MiB ± 15.3 MiB -0.09 %
threejs_production-mode_10x_persistent-hot + rss memory 369 MiB ± 4.27 MiB 371 MiB ± 11.7 MiB +0.70 %
threejs_production-mode_10x_source-map + rss memory 742 MiB ± 15.1 MiB 740 MiB ± 17.4 MiB -0.22 %

Base persistent cache hit rate: 👍

Current persistent cache hit rate: 👍

@github-actions

Copy link
Copy Markdown
Contributor

📦 Binary Size-limit

Comparing c12724a to chore(deps): update dependency webpack-sources to v3.5.1 (#14750) by renovate[bot]

🎉 Size decreased by 4.00KB from 66.50MB to 66.50MB (⬇️0.01%)

@codspeed-hq

codspeed-hq Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 43 untouched benchmarks
⏩ 47 skipped benchmarks1


Comparing perf/esm-linking (c12724a) with main (cd0781d)

Open in CodSpeed

Footnotes

  1. 47 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.

@JSerFeng

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

Reviewed commit: c12724aefe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@JSerFeng JSerFeng marked this pull request as ready for review July 14, 2026 04:07
Copilot AI review requested due to automatic review settings July 14, 2026 04:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes the ESM library linking pipeline in rspack_plugin_esm_library by removing redundant async work and avoiding repeated collection cloning during linking passes, reducing wall-clock time and allocation pressure in large module graphs.

Changes:

  • Removed an unused per-module output-path resolution pass performed before parallel module analysis.
  • Reworked namespace-object propagation to use an insertion-ordered worklist (index-based) instead of cloning the full set each iteration.
  • Avoided cloning hoisted_modules during link traversal by iterating by reference and copying identifiers only where needed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@JSerFeng JSerFeng merged commit 10840b8 into main Jul 14, 2026
39 checks passed
@JSerFeng JSerFeng deleted the perf/esm-linking branch July 14, 2026 05:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants