Skip to content

refactor(javascript): migrate parser to SWC Next - #15331

Draft
LingyuCoder wants to merge 43 commits into
mainfrom
seal/swc-next-parser-migration
Draft

refactor(javascript): migrate parser to SWC Next#15331
LingyuCoder wants to merge 43 commits into
mainfrom
seal/swc-next-parser-migration

Conversation

@LingyuCoder

@LingyuCoder LingyuCoder commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • replace the swc_experimental_* JavaScript analysis parser, AST, semantic model, walkers, evaluator, and parser plugins directly with SWC Next without introducing a compatibility crate or runtime backend switch
  • use the published SWC Next 0.1.3 crates from crates.io; all direct and transitive swc_next_* packages are registry dependencies pinned by Cargo.lock checksums
  • keep arena-backed AST and semantic handles within parser lifetimes and move scope-hoisting consumers to owned analysis results
  • preserve the latest main parser behavior, including dynamic imports in Promise.all destructuring, while updating parse-error diagnostic expectations for SWC Next wording and rendering
  • allocate shared diagnostic source text only when a parse diagnostic is emitted, avoiding a successful-parse source clone
  • stream arena-backed statement and property ranges directly into parser walkers instead of collecting temporary vectors

Validation:

  • rebased onto main commit c1ca9e2c323d9cdec8d510dfba4d15d081955737
  • cargo clippy --workspace --all-targets --tests --locked -- -D warnings
  • cargo deny --all-features check license bans
  • cargo xtask deny-ext
  • cargo test -p rspack_plugin_javascript --lib --locked (48 passed)
  • cargo fmt --all -- --check
  • pnpm run build:binding:dev
  • pnpm run lint:js
  • targeted object-properties, scope-hoisting, ESM library, JSX, cache, and static dynamic import tests
  • pnpm run test:unit (Rspack core: 9135 passed, 4 existing skipped; CLI: 89 passed, 1 existing skipped; node binding type test passed)

Known upstream limitation:

  • swc_next_ecma_ast 0.1.3 unconditionally rejects big-endian targets in its AST FFI, so the s390x build case is temporarily skipped until upstream supports that target; no JavaScript correctness cases are skipped

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).

@LingyuCoder
LingyuCoder force-pushed the seal/swc-next-parser-migration branch 2 times, most recently from d87ae01 to 0e5aafe Compare August 25, 2026 09:40

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0e5aafe25f

ℹ️ 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".

Comment thread crates/rspack_plugin_javascript/src/visitors/dependency/parser/walk.rs Outdated
Comment thread crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs
Comment thread crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs
@LingyuCoder
LingyuCoder force-pushed the seal/swc-next-parser-migration branch from 0e5aafe to ebe5ec8 Compare August 25, 2026 09:46

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ebe5ec8a3f

ℹ️ 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".

Comment thread crates/rspack_plugin_javascript/src/parser_plugin/side_effects_parser_plugin.rs Outdated
@LingyuCoder
LingyuCoder marked this pull request as draft August 25, 2026 10:08
@LingyuCoder
LingyuCoder force-pushed the seal/swc-next-parser-migration branch 3 times, most recently from 4af7d71 to 65f5e0e Compare August 25, 2026 11:12
@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

📦 Binary Size-limit

Comparing 6f58f90 to fix(core): align module need_build and FileSystemInfo with webpack (#15374) by hardfist

🎉 Size decreased by 856.00KB from 68.30MB to 67.47MB (⬇️1.22%)

@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Rsdoctor Bundle Diff Analysis

⚠️ Note: The latest commit (a338733507) does not have baseline artifacts. Using commit ced05ad339 for baseline comparison instead. If this seems incorrect, please wait a few minutes and try rerunning the workflow.

Found 5 projects in monorepo, 5 projects with changes.

📊 Quick Summary
Project Total Size Gzip Size Change Gzip Change
popular-libs 1.7 MB 556.5 KB -26.0 B (-0.0%) -1.0 B (-0.0%)
react-1k 823.0 KB 218.4 KB -26.0 B (-0.0%) -3.0 B (-0.0%)
ui-components 4.9 MB 1.4 MB -682.0 B (-0.0%) -171.0 B (-0.0%)
react-5k 2.7 MB 669.3 KB -26.0 B (-0.0%) -3.0 B (-0.0%)
react-10k 5.6 MB 1.3 MB -26.0 B (-0.0%) -3.0 B (-0.0%)
📋 Detailed Reports (Click to expand)

📁 popular-libs

Path: ../build-tools-performance/cases/popular-libs/dist/rsdoctor-data.json

📌 Baseline Commit: ced05ad339 | PR: #15377

Metric Current Baseline Change
📊 Total Size 1.7 MB 1.7 MB -26.0 B (-0.0%)
🗜️ Gzip Size 556.5 KB 556.5 KB -1.0 B (-0.0%)
📄 JavaScript 1.7 MB 1.7 MB -26.0 B (-0.0%)
🎨 CSS 0 B 0 B 0
🌐 HTML 289.0 B 289.0 B 0
📁 Other Assets 0 B 0 B 0

📦 Download Diff Report: popular-libs Bundle Diff

📁 react-1k

Path: ../build-tools-performance/cases/react-1k/dist/rsdoctor-data.json

📌 Baseline Commit: ced05ad339 | PR: #15377

Metric Current Baseline Change
📊 Total Size 823.0 KB 823.1 KB -26.0 B (-0.0%)
🗜️ Gzip Size 218.4 KB 218.4 KB -3.0 B (-0.0%)
📄 JavaScript 822.7 KB 822.7 KB -26.0 B (-0.0%)
🎨 CSS 0 B 0 B 0
🌐 HTML 328.0 B 328.0 B 0
📁 Other Assets 0 B 0 B 0

📦 Download Diff Report: react-1k Bundle Diff

📁 ui-components

Path: ../build-tools-performance/cases/ui-components/dist/rsdoctor-data.json

📌 Baseline Commit: ced05ad339 | PR: #15377

Metric Current Baseline Change
📊 Total Size 4.9 MB 4.9 MB -682.0 B (-0.0%)
🗜️ Gzip Size 1.4 MB 1.4 MB -171.0 B (-0.0%)
📄 JavaScript 4.8 MB 4.8 MB -682.0 B (-0.0%)
🎨 CSS 112.5 KB 112.5 KB 0
🌐 HTML 328.0 B 328.0 B 0
📁 Other Assets 0 B 0 B 0

📦 Download Diff Report: ui-components Bundle Diff

📁 react-5k

Path: ../build-tools-performance/cases/react-5k/dist/rsdoctor-data.json

📌 Baseline Commit: ced05ad339 | PR: #15377

Metric Current Baseline Change
📊 Total Size 2.7 MB 2.7 MB -26.0 B (-0.0%)
🗜️ Gzip Size 669.3 KB 669.3 KB -3.0 B (-0.0%)
📄 JavaScript 2.7 MB 2.7 MB -26.0 B (-0.0%)
🎨 CSS 21.0 B 21.0 B 0
🌐 HTML 328.0 B 328.0 B 0
📁 Other Assets 0 B 0 B 0

📦 Download Diff Report: react-5k Bundle Diff

📁 react-10k

Path: ../build-tools-performance/cases/react-10k/dist/rsdoctor-data.json

📌 Baseline Commit: ced05ad339 | PR: #15377

Metric Current Baseline Change
📊 Total Size 5.6 MB 5.6 MB -26.0 B (-0.0%)
🗜️ Gzip Size 1.3 MB 1.3 MB -3.0 B (-0.0%)
📄 JavaScript 5.6 MB 5.6 MB -26.0 B (-0.0%)
🎨 CSS 21.0 B 21.0 B 0
🌐 HTML 328.0 B 328.0 B 0
📁 Other Assets 0 B 0 B 0

📦 Download Diff Report: react-10k Bundle Diff

🤖 AI Degradation Analysis (Click to expand)

📁 popular-libs

📊 Size Changes

No significant regressions detected 🎉. Total bundle size decreased slightly from 1,821,866 bytes to 1,821,840 bytes (-26 bytes). Initial JS chunk remains stable at ~1.82 MB.

🔍 Root Cause Analysis

  • react-router@7.18.2: Minor parsedSize fluctuation (-26 bytes) within chunk-62JRHF6Z.mjs, likely build noise rather than code change.
  • No new modules added or removed.

⚠️ Risk Assessment

Overall severity: Low

  • Initial chunk size is effectively unchanged, ensuring no impact on Time to Interactive or load performance.

💡 Optimization Suggestions

  1. Merge & Deploy: No blocking performance issues; safe to merge.
  2. Monitor Dependencies: Keep an eye on future react-router major updates for potential tree-shaking improvements.
  3. Audit Intervals: Continue regular bundle audits to catch accumulation of technical debt early.

Analysis by qwen3.5-plus

📁 react-1k

📊 Size Changes

Asset / Chunk Baseline Current Δ Size Δ % Initial?
No significant regressions detected 🎉 - - - - -

🔍 Root Cause Analysis

  • Total bundle size decreased by 26 bytes (0.003%).
  • react-router v7.18.2 parsed size reduced slightly (35,481 → 35,455 bytes).
  • No new modules or dependencies added.

⚠️ Risk Assessment

Overall severity: Low

  • Initial chunk size decreased (776,474 → 776,448 bytes), ensuring no negative impact on FCP or total load time.

💡 Optimization Suggestions

  1. No action required; this PR is performance-neutral.
  2. Continue monitoring react-router updates for potential tree-shaking improvements in future versions.

Analysis by qwen3.5-plus

📁 ui-components

📊 Size Changes

No significant regressions detected 🎉.

🔍 Root Cause Analysis

  • Total Bundle: Decreased by 682 bytes (5,138,933 → 5,138,251).
  • @vueuse/core: Parsed size reduced 3,132 → 3,035 bytes (-3.1%).
  • @zag-js/select: Parsed size reduced 21,065 → 20,936 bytes.
  • Initial JS: Decreased 5,023,373 → 5,022,691 bytes.

⚠️ Risk Assessment

Overall severity: Low

  • Initial chunk size decreased slightly; no negative impact on load performance or regressions >5%.

💡 Optimization Suggestions

  1. Maintain current tree-shaking configuration for @vueuse/core to preserve gains.
  2. Monitor @rc-component/motion (parsed size +7 bytes) if updated in future releases.
  3. No immediate action required; safe to merge.

Analysis by qwen3.5-plus

📁 react-5k

📊 Size Changes

No meaningful change detected. Total bundle size decreased negligibly by 26 bytes (2.79 MB → 2.79 MB). No regressions >5% or >10 KB found 🎉.

🔍 Root Cause Analysis

  • Minor variance in react-router parsed size (35,481 → 35,455 bytes) due to build hashing or internal patching.
  • No new modules or duplicate dependencies introduced.

⚠️ Risk Assessment

Overall severity: Low

  • Initial chunk size decreased by 26 bytes; zero impact on Time to Interactive or load performance.

💡 Optimization Suggestions

  1. No action required; bundle health is stable.
  2. Continue monitoring react-router updates for potential major version upgrades if further optimization is needed.

Analysis by qwen3.5-plus

📁 react-10k

📊 Size Changes

No significant regressions detected 🎉.
Win: Total JS bundle decreased slightly (5,860,720 → 5,860,694 bytes; -26 bytes). Initial JS also decreased (746,165 → 746,139 bytes).

🔍 Root Cause Analysis

  • Minor reduction driven by react-router parsed size change (35,481 → 35,455 bytes).
  • No new modules, dependencies, or duplicates introduced.

⚠️ Risk Assessment

Overall severity: Low

  • Total bundle size delta is negligible (-26 bytes); no impact on initial load performance or user experience.

💡 Optimization Suggestions

  1. Safe to merge: No performance degradation detected.
  2. Monitor: Keep an eye on react-router updates to ensure continued tree-shaking efficiency.
  3. Maintain: Current bundling configuration is stable; no immediate code-splitting actions required.

Analysis by qwen3.5-plus

Generated by Rsdoctor GitHub Action

@codspeed-hq

codspeed-hq Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will improve performance by 11.18%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 7 improved benchmarks
✅ 43 untouched benchmarks
⏩ 47 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation rust@scan_dependencies@three_module 12.9 ms 9.3 ms +38.61%
Simulation bundle@threejs-production-sourcemap 191.4 ms 174.4 ms +9.74%
Simulation bundle@threejs-development 123.7 ms 113.1 ms +9.45%
Simulation bundle@basic-react-development 151.7 ms 141.7 ms +7.01%
Simulation bundle@misc-production-sourcemap 3.6 s 3.4 s +5.8%
Simulation bundle@misc-development 2.8 s 2.6 s +5.61%
Simulation bundle@basic-react-production-sourcemap 136.2 ms 129.1 ms +5.49%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing seal/swc-next-parser-migration (6f58f90) with main (a338733)

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.

@LingyuCoder
LingyuCoder force-pushed the seal/swc-next-parser-migration branch 2 times, most recently from b59f259 to 749e39b Compare August 25, 2026 13:42
@LingyuCoder

This comment was marked as outdated.

@codspeed-hq

This comment was marked as outdated.

@LingyuCoder

This comment was marked as off-topic.

@codspeed-hq

This comment was marked as off-topic.

@LingyuCoder

This comment was marked as outdated.

@web-infra-dev web-infra-dev deleted a comment from codspeed-hq Bot Aug 26, 2026
@codspeed-hq

This comment was marked as outdated.

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

📝 Benchmark detail: Open

Name Base (c1ca9e2) Current Change
10000_big_production-mode_disable-minimize + exec 11.8 s ± 240 ms 11.4 s ± 167 ms -3.23 %
10000_development-mode + exec 868 ms ± 19 ms 856 ms ± 14 ms -1.38 %
10000_development-mode_hmr + stats 169 ms ± 15 ms 158 ms ± 7.9 ms -6.80 %
10000_development-mode_noop-loader + exec 1.81 s ± 106 ms 1.79 s ± 102 ms -1.43 %
10000_production-mode + exec 1.05 s ± 39 ms 1.02 s ± 23 ms -2.03 %
10000_production-mode_persistent-cold + exec 1.2 s ± 41 ms 1.17 s ± 7.5 ms -3.02 %
10000_production-mode_persistent-hot + exec 643 ms ± 75 ms 636 ms ± 97 ms -1.03 %
10000_production-mode_source-map + exec 1.21 s ± 26 ms 1.19 s ± 38 ms -1.56 %
arco-pro_development-mode + exec 1.3 s ± 101 ms 1.32 s ± 74 ms +1.17 %
arco-pro_development-mode_hmr + stats 34 ms ± 1.4 ms 33 ms ± 1.1 ms -2.92 %
arco-pro_production-mode + exec 2.37 s ± 82 ms 2.3 s ± 95 ms -3.01 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 2.44 s ± 82 ms 2.42 s ± 105 ms -0.54 %
arco-pro_production-mode_persistent-cold + exec 2.41 s ± 47 ms 2.37 s ± 135 ms -1.47 %
arco-pro_production-mode_persistent-hot + exec 347 ms ± 7.5 ms 340 ms ± 6 ms -1.96 %
arco-pro_production-mode_source-map + exec 2.74 s ± 101 ms 2.7 s ± 108 ms -1.39 %
arco-pro_production-mode_source-map_persistent-cold + exec 2.9 s ± 36 ms 2.78 s ± 66 ms -4.17 %
arco-pro_production-mode_source-map_persistent-hot + exec 469 ms ± 4.3 ms 460 ms ± 12 ms -1.88 %
arco-pro_production-mode_traverse-chunk-modules + exec 2.41 s ± 137 ms 2.34 s ± 119 ms -2.66 %
bundled-threejs_development-mode + exec 183 ms ± 6.5 ms 173 ms ± 3.1 ms -5.46 %
bundled-threejs_production-mode + exec 214 ms ± 3.6 ms 200 ms ± 5.1 ms -6.54 %
large-dyn-imports_development-mode + exec 1.15 s ± 38 ms 1.16 s ± 44 ms +1.25 %
large-dyn-imports_production-mode + exec 1.3 s ± 58 ms 1.27 s ± 27 ms -2.21 %
threejs_development-mode_10x + exec 801 ms ± 21 ms 794 ms ± 17 ms -0.82 %
threejs_development-mode_10x_hmr + stats 113 ms ± 2.4 ms 107 ms ± 4.7 ms -5.40 %
threejs_production-mode_10x + exec 2.88 s ± 108 ms 2.82 s ± 50 ms -2.13 %
threejs_production-mode_10x_persistent-cold + exec 2.98 s ± 37 ms 2.94 s ± 44 ms -1.45 %
threejs_production-mode_10x_persistent-hot + exec 391 ms ± 19 ms 380 ms ± 6.6 ms -3.01 %
threejs_production-mode_10x_source-map + exec 3.61 s ± 147 ms 3.55 s ± 23 ms -1.61 %
10000_big_production-mode_disable-minimize + rss memory 2190 MiB ± 40.1 MiB 2123 MiB ± 52.2 MiB -3.02 %
10000_development-mode + rss memory 475 MiB ± 11.7 MiB 466 MiB ± 4.8 MiB -2.02 %
10000_development-mode_hmr + rss memory 719 MiB ± 18 MiB 705 MiB ± 41.4 MiB -2.05 %
10000_development-mode_noop-loader + rss memory 744 MiB ± 22.3 MiB 739 MiB ± 9.76 MiB -0.64 %
10000_production-mode + rss memory 468 MiB ± 10.9 MiB 463 MiB ± 10.2 MiB -0.99 %
10000_production-mode_persistent-cold + rss memory 620 MiB ± 9.35 MiB 622 MiB ± 7.6 MiB +0.27 %
10000_production-mode_persistent-hot + rss memory 594 MiB ± 33.5 MiB 589 MiB ± 40.4 MiB -0.82 %
10000_production-mode_source-map + rss memory 485 MiB ± 13.2 MiB 474 MiB ± 10 MiB -2.13 %
arco-pro_development-mode + rss memory 391 MiB ± 8.03 MiB 388 MiB ± 1.28 MiB -0.63 %
arco-pro_development-mode_hmr + rss memory 422 MiB ± 24.2 MiB 416 MiB ± 19.2 MiB -1.46 %
arco-pro_production-mode + rss memory 576 MiB ± 15.6 MiB 578 MiB ± 7.95 MiB +0.22 %
arco-pro_production-mode_generate-package-json-webpack-plugin + rss memory 590 MiB ± 16.8 MiB 596 MiB ± 12.2 MiB +1.00 %
arco-pro_production-mode_persistent-cold + rss memory 660 MiB ± 25.6 MiB 646 MiB ± 15.7 MiB -2.03 %
arco-pro_production-mode_persistent-hot + rss memory 277 MiB ± 5.32 MiB 279 MiB ± 9.74 MiB +0.67 %
arco-pro_production-mode_source-map + rss memory 680 MiB ± 18.9 MiB 679 MiB ± 13.4 MiB -0.22 %
arco-pro_production-mode_source-map_persistent-cold + rss memory 807 MiB ± 22.9 MiB 800 MiB ± 21 MiB -0.87 %
arco-pro_production-mode_source-map_persistent-hot + rss memory 395 MiB ± 6.8 MiB 395 MiB ± 8.4 MiB -0.09 %
arco-pro_production-mode_traverse-chunk-modules + rss memory 571 MiB ± 10.2 MiB 577 MiB ± 9.54 MiB +1.09 %
bundled-threejs_development-mode + rss memory 122 MiB ± 7.67 MiB 113 MiB ± 1.29 MiB -7.72 %
bundled-threejs_production-mode + rss memory 139 MiB ± 3.84 MiB 128 MiB ± 3.91 MiB -8.29 %
large-dyn-imports_development-mode + rss memory 496 MiB ± 19.6 MiB 488 MiB ± 14.4 MiB -1.53 %
large-dyn-imports_production-mode + rss memory 421 MiB ± 7.36 MiB 419 MiB ± 6.63 MiB -0.58 %
threejs_development-mode_10x + rss memory 425 MiB ± 16.8 MiB 428 MiB ± 17.5 MiB +0.72 %
threejs_development-mode_10x_hmr + rss memory 587 MiB ± 13.8 MiB 580 MiB ± 16.6 MiB -1.22 %
threejs_production-mode_10x + rss memory 631 MiB ± 12.1 MiB 644 MiB ± 11.7 MiB +2.12 %
threejs_production-mode_10x_persistent-cold + rss memory 573 MiB ± 10.2 MiB 582 MiB ± 10 MiB +1.61 %
threejs_production-mode_10x_persistent-hot + rss memory 368 MiB ± 1.06 MiB 385 MiB ± 7.27 MiB +4.68 %
threejs_production-mode_10x_source-map + rss memory 757 MiB ± 19.4 MiB 706 MiB ± 8 MiB -6.73 %

Base persistent cache hit rate: 👍

Current persistent cache hit rate: 👍

@LingyuCoder
LingyuCoder force-pushed the seal/swc-next-parser-migration branch from 696f5b8 to cf3db7b Compare August 28, 2026 07:33
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 28, 2026

Copy link
Copy Markdown

Deploying rspack with  Cloudflare Pages  Cloudflare Pages

Latest commit: cf3db7b
Status: ✅  Deploy successful!
Preview URL: https://d4411bed.rspack-v2.pages.dev
Branch Preview URL: https://seal-swc-next-parser-migrati.rspack-v2.pages.dev

View logs

@LingyuCoder

Copy link
Copy Markdown
Contributor Author

@codspeedbot explain why rust@scan_dependencies is faster

@codspeed-hq

codspeed-hq Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

@codspeedbot explain why rust@scan_dependencies is faster

@codspeedbot explain why rust@scan_dependencies is faster

I profiled this benchmark specifically (head cf3db7b vs main aa2ea64): 12.86 ms → 9.89 ms (−23% instructions, the +30.06% efficiency in the report).

First, the important scoping detail: this benchmark cannot be measuring the parser swap. In xtask/benchmark/benches/groups/scan_dependencies.rs, the parse and the semantic analysis run once in setup (the AST and Semantic are leaked and reused by every iteration); the measured region is only scan_dependenciesJavascriptParser::walk_program + into_results. The faster SWC Next lexer never runs inside the measured window here. So this number is a pure dependency-walker result.

The bench is also very low-noise — two consecutive main commits measured 12.8575 ms and 12.8527 ms (0.04% apart) — so the step is real.

Where the −3.0 ms sits

Block BASE HEAD Δ
scan_dependencies (measured region) 12.8 ms 9.8 ms −3.0
walk_module_items (the statement/expression walk) 10.8 ms 7.8 ms −3.0
block_pre_walk_module_item 813 µs 833 µs +0.02
into_results (inner-graph finalization) ~445 µs 369 µs −0.08

The entire delta is in the main walk; the pre-walk phases and the location advancer (memchr 293 → 304 µs) are flat, which confirms nothing moved out of the measured region.

What actually got cheaper in the walk

  • Bindings are read from the semantic model instead of being rediscovered. Base called ScopeInfoDB::exit_scope per block and walked declaration patterns to find bindings; head calls WebpackVariableEnvironment::_create + activate_semantic_scope_bindings, which iterates the symbols SWC Next already resolved (lexical ownership and var/function hoisting).
  • The scope table is dense. SlotMap<ScopeInfoId, ScopeInfo> with a per-scope Vec<Atom> defined became a Vec-indexed NonZeroU32 id space with one shared "defined" log and &str lookups — one allocation and one hash probe less per scope, and no Atom materialization per lookup.
  • Patterns are borrowed, not collected. The class subtree went 2.9 → 2.1 ms, and the instantiation changed from in_class_scope::<alloc::vec::into_iter::IntoIter<PatRef>, …> to in_class_scope::<core::option::IntoIter<PatRef>, …>, with enter_pattern::<… PatRef::Borrowed …> — the temporary Vec<PatRef> per class/function is gone. The extra per-statement frame walk_statement::{closure#1} (10.7 ms inclusive in base) is gone too.
  • Inner-graph state is index-based. HashMap<TopLevelSymbol, InnerGraphMapValue> + HashSet churn (finalize_dependency_usage 444.8 µs) became Vec<TopLevelSymbolState> + SmallVec<[_; 2]> sets (into_results 368.9 µs total).

The win came from the follow-up commits, not the migration itself

Same benchmark, along the branch:

Commit Value
main 12.86 ms
0ae59f7 refactor: migrate parser to swc next 14.39 ms (+12% slower)
375fe37 use dense parser state 11.46 ms
89c6295 reduce walker analysis overhead 10.48 ms
cf3db7b streamline parser walker hot paths (head) 9.89 ms

The raw port to the SWC Next AST made the walker slower; the −23% is entirely the semantic-reuse / dense-state / borrowed-pattern work layered on top.

Two caveats

  1. Because the semantic analysis lives in setup here, this bench shows the walker win at full size while charging none of the analysis it now leans on. In a real cold build that cost is paid in the parse phase: rust@build_module_graph is 438.4 → 436.9 ms on the same pair, essentially flat. The end-to-end evidence is the bundle cases (+4.9% … +9.6%) and the walltime CI run (bundled-threejs_development −5.5%, bundled-threejs_production −6.5%).
  2. Base and head ran on different runner CPUs (EPYC 7763 → 9V74), which is worth ~2% on Simulation — irrelevant at this magnitude, but worth knowing.

If you want more from this path, the clearest remaining item is Wtf8::to_string_lossy under evaluate_expression: 79.4 µs / 11 calls → 158.3 µs / 20 calls (141.5 µs self, ~1.4% of the bench). String-literal evaluation still materializes owned Strings from the arena's WTF-8 slices.

No code changes were needed — this is an analysis-only answer.

Summary
  • Warming up the performance wizard...
  • Explain why rust@scan_dependencies is faster — Compared head cf3db7b vs main aa2ea64 (12.86 ms -> 9.89 ms)
  • Attribute the speedup via flamegraphs — Whole delta localized to the statement walk; per-commit trajectory reconstructed
  • Report findings — Writing the analysis-only answer
  • Handling comment — Comment handling finished successfully

Learnings updated. See what CodSpeed remembers about this repository.

Was this response helpful? React with 👍 or 👎 to help us improve CodSpeedBot.

@LingyuCoder

Copy link
Copy Markdown
Contributor Author

@codspeedbot explain why bundle@threejs-production-sourcemap is faster

@codspeed-hq

codspeed-hq Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

@codspeedbot explain why bundle@threejs-production-sourcemap is faster

@codspeedbot explain why bundle@threejs-production-sourcemap is faster

I re-profiled this benchmark on the current head (cf3db7b) against main (aa2ea64): 191.3 ms → 174.6 ms, −16.7 ms (+9.55%). The picture has shifted since my earlier answer — the walker is now a real contributor, and the semantic phase got more expensive again.

Block BASE HEAD Δ
module build (BuildTaskNormalModule::build) 77.0 ms 66.2 ms −10.8
scope hoisting (ConcatenatedModule::code_generation) 45.3 ms 39.9 ms −5.4
everything else 69.0 ms 68.5 ms −0.5

1. Module build: −10.8 ms

All of it is inside JavaScriptParserAndGenerator::parse (74.9 → 64.1 ms):

Phase BASE HEAD
SWC parse 28.1 ms 18.1 ms
post-parse fixups (remove_paren walk ~1.2 + InsertedSemicolons visitor ~1.9) ~3.0 ms 1.1 ms (semicolon::collect token scan; strip_parenthesized_nodes 0.46 ms is folded into parse)
semantic 5.9 ms (legacy::resolver) 11.5 ms (swc_next_ecma_semantic::analyze)
dependency walker (scan_dependencies) 37.5 ms 32.7 ms
total 74.9 ms 64.1 ms

Three things to note:

  • Parsing is ~36% cheaper. The old path lexed through Capturing<Lexer>, materialising every TokenAndSpan; the new lexer does the same work without the capture buffer. The paren-removal AST walk and the inserted-semicolon AST visitor are gone, replaced by a pass inside parsing and a flat token scan.
  • The walker now wins too (37.5 → 32.7 ms; walk_module_items 30.6 → 25.7 ms), which it did not in my earlier analysis. This is the perf(javascript) follow-up commits: bindings come from the semantic model instead of being rediscovered, dense Vec-indexed scope state, borrowed patterns (base's extra per-statement walk_statement::{closure#1} frame is gone).
  • Semantic analysis got more expensive, and this is the flip side of the walker win. fix(javascript): restore semantic syntax diagnostics put the full swc_next_ecma_semantic::analyze (binder plus the early-error Checker) back on the build path after the name-resolver commit had replaced it: 5.9 → 11.5 ms, of which 9.2 ms is the Checker traversal (including regex-literal parsing via swc_next_regular_expression). Scope hoisting still uses the lighter name_resolver::resolver.

Net: on a cold build the walker's −4.8 ms roughly cancels the analyzer's +5.6 ms, so the module-build win is essentially the parser and the removed fixup passes.

2. Scope hoisting: −5.4 ms

This case is production + scope hoisting, so every module is parsed a second time, and that parse gets the same win:

  • per-module re-parse: 24.9 ms → 17.5 ms (−7.4)
  • scope resolution: legacy::resolver 5.9 ms → name_resolver::resolver 5.5 ms (−0.4)
  • NewConcatenatedModuleIdent::to_legacy: 1.8 ms → gone (owned analysis results)

Only −5.4 of that −9.6 survives, because identifier handling costs more: collect_ident 2.2 ms → IdentCollector 3.8 ms, plus more atom interning at the rspack boundary (hstr::wtf8_atom_in 1.7 → 2.1 ms, the Atom hashmap insert 0.77 → 1.3 ms, a new Atom::as_str 0.49 ms).

−10.8 and −5.4 account for −16.2 of the −16.7 ms.

Where the remaining headroom is

  1. The early-error Checker inside analyze — ~6 ms of the 174.6 ms here, paid on every module of every cold build. Scope hoisting already gets by with name_resolver::resolver at 5.5 ms; if the syntax diagnostics could be produced more cheaply (or only when something is likely to be reported), that is the single biggest lever left on this benchmark.
  2. Ident collection / atom interning in analyze_concatenated_module_identifiers — ~2 ms of clawback on the scope-hoisted cases.

One caveat: base and head ran on different runner CPUs (EPYC 7763 → 9V74), which is worth ~2% on Simulation — not material at a +9.55% delta, but worth knowing.

No code changes were needed; this is an analysis-only answer.

Summary
  • Warming up the performance wizard...
  • Explain bundle@threejs-production-sourcemap speedup — Compared head cf3db7b vs main aa2ea64 (191.3 -> 174.6 ms)
  • Attribute the delta via flamegraphs — Split into module build (-10.8 ms) and scope hoisting (-5.4 ms), with per-phase numbers
  • Report findings — Analysis-only answer; no code changes needed
  • Handling comment — Comment handling finished successfully

Learnings updated. See what CodSpeed remembers about this repository.

Was this response helpful? React with 👍 or 👎 to help us improve CodSpeedBot.

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.

1 participant