Skip to content

refactor: export lexical runtime globals for esm chunks#14741

Open
LingyuCoder wants to merge 9 commits into
mainfrom
seal/stacked-lexical-runtime-globals
Open

refactor: export lexical runtime globals for esm chunks#14741
LingyuCoder wants to merge 9 commits into
mainfrom
seal/stacked-lexical-runtime-globals

Conversation

@LingyuCoder

Copy link
Copy Markdown
Contributor

Summary

  • add a lexical runtime-global rendering mode for the ESM output + split runtime chunk case
  • export runtime module globals as lexical __rspack_* bindings from the runtime chunk instead of mounting them on __rspack_context
  • import those lexical bindings from runtime chunks at ESM library render/link sites, including setter helpers such as __rspack_set_*
  • refresh runtime-mode ESM output snapshots

Context

This is stacked on #14740. The base PR only enables the RuntimeModeEsmOutput context import coverage and fixes modern ESM chunk loading. This PR contains the lexical runtime-global export/import behavior needed for tree shaking when downstream consumers depend on the ESM output runtime chunk.

The behavior is scoped to output module builds using Rspack runtime mode with a split modern-module runtime chunk.

Checks

  • pnpm run build:binding:dev
  • pnpm run test:unit

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

📦 Binary Size-limit

Comparing 5a7c1f7 to fix: preserve createRequire().resolve with literal import.meta.url when requireResolve is disabled (#14783) by Fy

❌ Size increased by 73.25KB from 66.58MB to 66.65MB (⬆️0.11%)

@github-actions

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 551.5 KB - -
react-10k 5.6 MB 1.3 MB - -
react-5k 2.7 MB 663.8 KB - -
react-1k 823.1 KB 217.0 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 551.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-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 663.8 KB - -
📄 JavaScript 2.7 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 217.0 KB - -
📄 JavaScript 822.7 KB - -
🎨 CSS 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.1 KB - -
🌐 HTML 328.0 B - -
📁 Other Assets 0 B - -

Generated by Rsdoctor GitHub Action

Base automatically changed from seal/lexical-runtime-exports to main July 10, 2026 03:52
@LingyuCoder LingyuCoder changed the title fix: export lexical runtime globals for esm chunks refactor: export lexical runtime globals for esm chunks Jul 13, 2026
@LingyuCoder LingyuCoder changed the base branch from main to seal/runtime-template-render-modes July 13, 2026 11:45
@LingyuCoder LingyuCoder force-pushed the seal/runtime-template-render-modes branch from aa258ea to 0af5acb Compare July 13, 2026 13:39
@LingyuCoder LingyuCoder force-pushed the seal/stacked-lexical-runtime-globals branch from 2dbde1d to 40f063b Compare July 13, 2026 14:20
@codspeed-hq

codspeed-hq Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 43 untouched benchmarks
⏩ 47 skipped benchmarks1


Comparing seal/stacked-lexical-runtime-globals (5a7c1f7) with main (b8e3594)

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.

Base automatically changed from seal/runtime-template-render-modes to main July 14, 2026 04:52
@LingyuCoder LingyuCoder force-pushed the seal/stacked-lexical-runtime-globals branch from 40f063b to afc24cb Compare July 14, 2026 06:10
@LingyuCoder LingyuCoder marked this pull request as ready for review July 16, 2026 03:48
@LingyuCoder LingyuCoder requested a review from ahabhgk as a code owner July 16, 2026 03:48
Copilot AI review requested due to automatic review settings July 16, 2026 03:48

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 refactors Rspack “runtime mode” ESM output to export/import runtime globals as lexical bindings from the runtime chunk (instead of mounting them on __rspack_context), enabling better tree-shaking for downstream consumers when using split modern-module runtime chunks. It also introduces a systematic way to pre-reserve runtime-module-local variable names (derived from EJS templates) to prevent name collisions with user modules, and refreshes runtime-mode ESM snapshots accordingly.

Changes:

  • Switch runtime-mode ESM output from __rspack_context.* access to direct lexical imports/exports (e.g. rspackRequire, moduleFactories, definePropertyGetters, makeNamespaceObject, etc.).
  • Add “runtime module variable” extraction/registration (via EJS var() / fn() helpers + inventory registration) to reserve identifiers before runtime module instantiation and avoid userland naming conflicts.
  • Update runtime EJS templates and a large set of runtime-mode ESM output snapshots; add/adjust targeted test cases for collision and runtimeChunk=false scenarios.

Reviewed changes

Copilot reviewed 200 out of 202 changed files in this pull request and generated no comments.

Show a summary per file
File Description
crates/rspack_plugin_runtime/src/runtime_module/utils.rs Allow HMR runtime-state rendering in the new export-based render mode.
crates/rspack_plugin_runtime/src/runtime_module/startup_chunk_dependencies.rs Add runtime-module-variable extraction and stable template reuse for startup-chunk dependencies runtime module.
crates/rspack_plugin_runtime/src/runtime_module/runtime/startup_chunk_dependencies.ejs Convert top-level declaration to EJS var() to support identifier reservation/deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/require_chunk_loading.ejs Convert top-level var declaration to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/require_chunk_loading_with_hmr.ejs Convert top-level function declaration to EJS fn() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/readfile_chunk_loading.ejs Convert top-level var declaration to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/readfile_chunk_loading_with_hmr.ejs Convert top-level function declaration to EJS fn() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/on_chunk_loaded.ejs Convert top-level var declaration to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/module_chunk_loading.ejs Convert top-level var declaration to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/module_chunk_loading_with_hmr.ejs Convert top-level function declaration to EJS fn() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/load_script.ejs Convert top-level var declaration to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/jsonp_chunk_loading_with_hmr.ejs Convert top-level vars/functions to EJS var() / fn() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/jsonp_chunk_loading_with_callback.ejs Convert top-level vars to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/javascript_hot_module_replacement.ejs Convert top-level vars/functions to EJS var() / fn() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/import_scripts_chunk_loading.ejs Convert top-level vars to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/import_scripts_chunk_loading_with_hmr.ejs Convert top-level function to EJS fn() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/get_trusted_types_policy.ejs Convert top-level var to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/create_fake_namespace_object.ejs Convert top-level vars to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/chunk_preload_trigger.ejs Convert top-level var to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/chunk_prefetch_trigger.ejs Convert top-level var to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/runtime/auto_public_path.ejs Convert top-level vars to EJS var() for deconfliction.
crates/rspack_plugin_runtime/src/runtime_module/require_js_chunk_loading.rs Register runtime-module variables extracted from templates; reserve additional internal vars.
crates/rspack_plugin_runtime/src/runtime_module/readfile_chunk_loading.rs Register runtime-module variables extracted from templates; reserve additional internal vars.
crates/rspack_plugin_runtime/src/runtime_module/on_chunk_loaded.rs Register runtime-module variables and reuse template string constant.
crates/rspack_plugin_runtime/src/runtime_module/load_script.rs Register runtime-module variables; reserve additional internal vars.
crates/rspack_plugin_runtime/src/runtime_module/jsonp_chunk_loading.rs Register runtime-module variables; reserve additional internal vars.
crates/rspack_plugin_runtime/src/runtime_module/get_trusted_types_policy.rs Register runtime-module variables and reuse template string constant.
crates/rspack_plugin_runtime/src/runtime_module/export_require.rs Register runtime-module variables for temp export names used by the module.
crates/rspack_plugin_runtime/src/runtime_module/create_fake_namespace_object.rs Register runtime-module variables extracted from the EJS template.
crates/rspack_plugin_runtime/src/runtime_module/chunk_preload_trigger.rs Register runtime-module variables extracted from the EJS template.
crates/rspack_plugin_runtime/src/runtime_module/chunk_prefetch_trigger.rs Register runtime-module variables extracted from the EJS template.
crates/rspack_plugin_runtime/src/runtime_module/auto_public_path.rs Register runtime-module variables extracted from the EJS template.
crates/rspack_plugin_runtime/src/runtime_module/async_module.rs Register runtime-module variables and treat export render mode as lexical-capable.
crates/rspack_plugin_runtime/src/helpers.rs Add extraction of runtime-module variable names from EJS var()/fn() usage + unit test.
crates/rspack_plugin_mf/src/sharing/share_runtime_module.rs Register runtime-module variables extracted from sharing EJS template.
crates/rspack_plugin_mf/src/sharing/initializeSharing.ejs Convert top-level var declarations to EJS var() for deconfliction.
crates/rspack_plugin_mf/src/sharing/consume_shared_runtime_module.rs Register runtime-module variables extracted from multiple consume-sharing templates.
crates/rspack_plugin_mf/src/container/embed_federation_runtime_module.rs Register runtime-module variables extracted from federation embed templates; reuse template constants.
crates/rspack_plugin_mf/src/container/embed_federation_runtime_sync.ejs Convert top-level var declarations to EJS var() for deconfliction.
crates/rspack_plugin_mf/src/container/embed_federation_runtime_async.ejs Convert top-level var declarations to EJS var() for deconfliction.
crates/rspack_plugin_hmr/src/hot_module_replacement.rs Register runtime-module variables extracted from HMR EJS template.
crates/rspack_plugin_extract_css/src/runtime/css_loading.ejs Convert top-level declarations to EJS var(); adjust to use _get_chunk_css_filename helper variable.
crates/rspack_plugin_extract_css/src/runtime/css_loading_with_preload_link.ejs Switch to _get_chunk_css_filename for CSS href generation.
crates/rspack_plugin_extract_css/src/runtime/css_loading_with_prefetch_link.ejs Switch to _get_chunk_css_filename for CSS href generation.
crates/rspack_plugin_extract_css/src/runtime/css_loading_with_loading.ejs Convert installedCssChunks to EJS var() for deconfliction.
crates/rspack_plugin_extract_css/src/runtime/css_loading_with_hmr.ejs Convert top-level vars to EJS var(); switch to _get_chunk_css_filename.
crates/rspack_plugin_extract_css/src/plugin.rs Use a custom export-global name for mini-css chunk filename under export render mode.
crates/rspack_plugin_esm_library/src/runtime.rs Register runtime-module variables for ESM chunk loading runtime module.
crates/rspack_plugin_esm_library/src/render/runtime_mode/webpack.rs Add a dedicated webpack-mode runtime renderer for ESM library runtime-mode output.
crates/rspack_plugin_css/src/runtime/mod.rs Register runtime-module variables extracted from CSS runtime templates; reserve internal var.
crates/rspack_plugin_css/src/runtime/css_loading.ejs Convert top-level declarations to EJS var()/fn() for deconfliction.
crates/rspack_plugin_css/src/runtime/css_loading_with_style.ejs Convert top-level functions/vars to EJS fn()/var() for deconfliction.
crates/rspack_plugin_css/src/runtime/css_loading_with_hmr.ejs Convert top-level vars to EJS var() for deconfliction.
crates/rspack_macros/src/runtime_module.rs Extend #[impl_runtime_module] macro to optionally register runtime-module-variable providers via inventory.
crates/rspack_core/src/runtime_module.rs Add runtime-module-variable provider plumbing (inventory collection + iterator).
crates/rspack_core/src/runtime_globals.rs Add Rspack-export runtime variable naming and setter-name helper generation.
crates/rspack_core/src/lib.rs Re-export inventory for macro-generated registrations.
crates/rspack_core/src/dependency/mod.rs Export write-operation type used by runtime requirements dependency templates.
crates/rspack_core/src/compilation/build_module_graph/graph_updater/repair/context.rs Ensure runtime_template is initialized during compilation repair context setup.
crates/rspack_core/src/artifacts/runtime_proxy_metadata_artifact.rs Generalize lexical declaration rendering to allow name-mapping injection.
crates/rspack_core/Cargo.toml Add inventory dependency for runtime-module-variable registration.
Cargo.lock Lockfile update for new inventory dependency usage.
crates/rspack_plugin_javascript/src/runtime.rs Export should_export_rspack_runtime_globals from runtime context.
crates/rspack_plugin_javascript/src/parser_plugin/import_meta_plugin.rs Adjust import-meta assignment handling to propagate assignment op + rhs span into helper.
tests/rspack-test/esmOutputCases/**/snapshots/runtimeModeSnapshot/esm.snap.txt Refresh runtime-mode ESM output snapshots to reflect lexical runtime-global exports/imports.
tests/rspack-test/esmOutputCases/basic/split-runtime-chunk/index.js Add assertion around publicPath mutation behavior when splitting runtime chunk.
tests/rspack-test/esmOutputCases/basic/split-runtime-chunk/snapshots/esm.snap.txt Refresh baseline (non-runtime-mode) snapshot to include publicPath mutation expectations.
tests/rspack-test/esmOutputCases/interop/runtime-module-variable-conflict/rspack.config.js New test config to exercise runtime module variable name deconfliction.
tests/rspack-test/esmOutputCases/interop/runtime-module-variable-conflict/index.js New test asserting userland bindings don’t conflict with runtime module variables.
tests/rspack-test/esmOutputCases/interop/runtime-module-variable-conflict/foo.mjs New fixture module for the conflict test case.
tests/rspack-test/esmOutputCases/dynamic-import/import-cjs-runtime-chunk-false-entry-export/test.config.js New test assertions ensuring runtimeChunk=false output doesn’t export rspack runtime globals.
tests/rspack-test/esmOutputCases/dynamic-import/import-cjs-runtime-chunk-false-async-chunk/test.config.js Update expectations for runtime-mode ESM output to use lexical imports/exports and avoid re-exporting runtime bindings.
tests/rspack-test/esmOutputCases/basic/runtime-chunk-false/test.config.js New test assertions ensuring runtimeChunk=false runtime-mode output avoids exporting __rspack_* globals.
tests/rspack-test/configCases/**/snapshot/runtimeModeSnapshot/*.txt Refresh runtime-mode snapshots for config cases impacted by the new lexical runtime-global rendering.

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

@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: 5a7c1f74a4

ℹ️ 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 +260 to +262
sources.add(RawStringSource::from(render_rspack_runtime_exports(
context_fields,
context_fields.intersection(setters),

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 Emit setters for module-only runtime writes

In RspackExport mode, render_runtime_global_specifiers imports setter helpers for every module write recorded in CodeGenerationRuntimeRequirementsWrite, but this call only emits a setter when the same runtime global is also present in a runtime module's define/force_context fields. For globals such as SCRIPT_NONCE (e.g. import.meta.rspackNonce = "n" or __webpack_require__.nc = "n") there is no defining runtime module, so a split modern-module runtime chunk declares no setScriptNonce export while the entry chunk imports/calls it, causing the ESM module to fail during linking.

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.

2 participants