Skip to content

fix: preserve faster module concatenation semantics - #15257

Closed
LingyuCoder wants to merge 3 commits into
mainfrom
seal/faster-concat-output-parity
Closed

LingyuCoder wants to merge 3 commits into
mainfrom
seal/faster-concat-output-parity

Conversation

@LingyuCoder

Copy link
Copy Markdown
Contributor

Summary

  • Fall back to legacy codegen-time scope analysis when non-compile-time DefinePlugin replacements or ambiguous top-level for-in/for-of assignment heads cannot be represented safely by make-time scope metadata.
  • Preserve binding relationships for globals materialized by ProvidePlugin, and keep default-exported namespace expressions intact when dependency templates overlap.
  • Keep faster-concatenation used-name metadata accurate without treating static PureExpression wrapper code as generated identifiers.

Related links

Validation

  • pnpm run build:binding:dev
  • pnpm run test:unit (9224 passed, 4 skipped)
  • cargo fmt --all --check
  • cargo check -p rspack_core -p rspack_plugin_javascript
  • Faster on/off comparison for all five rstackjs/build-tools-performance projects; complete output trees are byte-for-byte identical
  • Faster on/off Dreamina production builds; stable executable assets are identical, with only the previously confirmed dependency-order nondeterminism and its hash/manifest/source-map cascades excluded

Checklist

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

@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

📦 Binary Size-limit

Comparing b09b0e7 to chore: update Rstack to v0.6.2 (#15252) by Jiahan Chen

❌ Size increased by 4.00KB from 68.15MB to 68.15MB (⬆️0.01%)

@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Rsdoctor Bundle Diff Analysis

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 - -
react-10k 5.6 MB 1.3 MB - -
react-1k 823.1 KB 218.4 KB - -
react-5k 2.7 MB 669.3 KB - -
ui-components 4.9 MB 1.4 MB - -
📋 Detailed Reports (Click to expand)

📁 popular-libs

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

⚠️ No baseline data found - Unable to perform comparison analysis

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

📁 react-10k

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

⚠️ No baseline data found - Unable to perform comparison analysis

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

📁 react-1k

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

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 823.1 KB - -
🗜️ Gzip Size 218.4 KB - -
📄 JavaScript 822.7 KB - -
🎨 CSS 0 B - -
🌐 HTML 328.0 B - -
📁 Other Assets 0 B - -

📁 react-5k

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

⚠️ No baseline data found - Unable to perform comparison analysis

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

📁 ui-components

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

⚠️ No baseline data found - Unable to perform comparison analysis

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

Generated by Rsdoctor GitHub Action

@codspeed

codspeed Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 50 untouched benchmarks
⏩ 47 skipped benchmarks1


Comparing seal/faster-concat-output-parity (b09b0e7) with main (f7a86ea)

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 marked this pull request as ready for review August 20, 2026 13:06

@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: b09b0e7f1d

ℹ️ 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 on lines +752 to +757
if let Some(concatenation_scope) = concatenation_scope.as_deref_mut()
&& let Some(request) = request
{
// The primary request is emitted as a free expression. Preserve its
// identifiers so concatenated bindings cannot capture the external.
concatenation_scope.register_used_names_from_generated_code(request.primary());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Track free names in every concatenatable external arm

When faster module concatenation is enabled, this reservation only covers the var/promise/const/let/assign and catch-all arms. Earlier concatenatable arms also emit free identifiers—for example, externalsType: "window" emits window[...], while commonjs emits require(...). A top-level window or require binding from another concatenated module can therefore capture the generated external expression and change which value is loaded. Reserve the identifiers emitted by those explicit arms as well.

Useful? React with 👍 / 👎.

.downcast_ref::<ProvideDependency>()
.expect("ProvideDependencyTemplate should only be used for ProvideDependency");
let rendered_identifier = source.ensure_generated_top_level_symbol(dep.identifier.clone());
let rendered_identifier = source.rebind_generated_global_symbol(dep.identifier.clone());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Rebind the provided global only after resolving its dependency

When a ProvidePlugin request fails to resolve with bail: false, the connection lookup below returns None and the template intentionally leaves the original global reference untouched. Registering RebindGlobal before that check nevertheless reclassifies matching globals as a generated top-level binding; because no declaration is emitted, a name collision with another concatenated module can rename the surviving global reference and make it resolve to an undefined identifier. Delay rebinding until after the connection has been found.

Useful? React with 👍 / 👎.

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