Skip to content

fix: skip esm interop for require() module outside the concatenation - #21884

Merged
alexander-akait merged 1 commit into
mainfrom
fix/concat-external-require-interop
Aug 31, 2026
Merged

fix: skip esm interop for require() module outside the concatenation#21884
alexander-akait merged 1 commit into
mainfrom
fix/concat-external-require-interop

Conversation

@hai-x

@hai-x hai-x commented Aug 31, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #21882.

Keep raw access for require() targets outside the concatenation. And no fake namespace is needed to keep ESM interop.

What kind of change does this PR introduce?

Fix

Did you add tests for your changes?

Yes

Does this PR introduce a breaking change?

No

If relevant, what needs to be documented once your changes are merged or what have you already documented?

n/a

Use of AI

Yes

Summary by CodeRabbit

  • Bug Fixes

    • Corrected require() behavior for modules outside concatenated bundles.
    • Preserved the original module exports instead of adding unnecessary ESM interop wrappers.
    • Improved handling of CommonJS modules, including default and named exports, when loaded from split chunks.
  • Tests

    • Added coverage for required assets and modules across separate bundles.
    • Verified that split-module imports return expected raw exports.

@changeset-bot

changeset-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8bb397e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
webpack Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d7ee7835-38a2-4f20-9b3f-77e00febe3da

📥 Commits

Reviewing files that changed from the base of the PR and between c961f61 and 8bb397e.

⛔ Files ignored due to path filters (1)
  • test/configCases/concatenate-modules/issue-21882/a.svg is excluded by !**/*.svg
📒 Files selected for processing (7)
  • .changeset/015-concat-external-require-interop.md
  • lib/optimize/ConcatenatedModule.js
  • test/configCases/concatenate-modules/issue-21882/consumer.js
  • test/configCases/concatenate-modules/issue-21882/data.js
  • test/configCases/concatenate-modules/issue-21882/index.js
  • test/configCases/concatenate-modules/issue-21882/test.config.js
  • test/configCases/concatenate-modules/issue-21882/webpack.config.js

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Changes

The concatenation export-resolution path now skips ESM interop for require() targets outside the concatenation. A new issue 21882 configuration builds split SVG and CommonJS modules and verifies raw exports plus concatenation boundaries.

Require interop correction

Layer / File(s) Summary
Skip interop for external require targets
lib/optimize/ConcatenatedModule.js, .changeset/015-concat-external-require-interop.md
moduleExportsAccess bypasses ESM interop before empty export-name resolution. The changeset declares a patch release.
Add issue 21882 regression case
test/configCases/concatenate-modules/issue-21882/*
The test configuration splits SVG and data.js modules. Tests verify raw require() results and the expected concatenated module set.

Merge Risk: ⚪ Minimal · up to 8bb39

This localized change adjusts generated require() behavior for modules outside concatenation and adds regression coverage; no actionable merge-blocking risk remains beyond normal checks and review.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive The implementation bypasses ESM interop for requires targeting modules outside concatenation. The added tests verify raw CommonJS exports, asset URL behavior, and split-module placement. Verification … Include the excluded SVG fixture in the review or provide its contents to verify the asset URL requirement fully.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title uses the required conventional-commit format with the allowed type fix and clearly describes the interop change.
Out of Scope Changes check ✅ Passed The source change, changeset, webpack configuration, and regression tests all directly support issue #21882. No unrelated changes are shown.
Full details: Linked Issues check

Explanation

The implementation bypasses ESM interop for requires targeting modules outside concatenation. The added tests verify raw CommonJS exports, asset URL behavior, and split-module placement. Verification of the excluded SVG fixture is incomplete because test/configCases/concatenate-modules/issue-21882/a.svg was filtered by !**/*.svg.

  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the area: optimization Tree-shaking, splitChunks, concatenation, ids (lib/optimize, lib/ids) label Aug 31, 2026
@hai-x
hai-x force-pushed the fix/concat-external-require-interop branch from 3b0a719 to 8bb397e Compare August 31, 2026 18:49
@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

This PR is packaged and the instant preview is available (5352fd8).

Install it locally:

  • npm
npm i -D webpack@https://pkg.pr.new/webpack@5352fd8
  • yarn
yarn add -D webpack@https://pkg.pr.new/webpack@5352fd8
  • pnpm
pnpm add -D webpack@https://pkg.pr.new/webpack@5352fd8

@github-actions

Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging fix/concat-external-require-interop into main will be
99.23%
Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
bin
   webpack.js98.82%100%100%98.82%103
examples
   build-common.js100%100%100%100%
   buildAll.js100%100%100%100%
   examples.js100%100%100%100%
   template-common.js98.21%100%100%98.21%72
examples/custom-javascript-parser
   test.filter.js100%100%100%100%
examples/custom-javascript-parser/internals
   acorn-parse.js100%100%100%100%
   meriyah-parse.js100%100%100%100%
   oxc-parse.js100%100%100%100%
examples/markdown
   webpack.config.mjs100%100%100%100%
examples/module-federation
   test.filter.js100%100%100%100%
examples/reexport-components
   test.filter.js100%100%100%100%
examples/typescript
   test.filter.js100%100%100%100%
examples/typescript-non-erasable
   test.filter.js50%100%100%50%5
examples/virtual-modules
   test.filter.js100%100%100%100%
examples/wasm-bindgen-esm
   test.filter.js100%100%100%100%
examples/wasm-complex
   test.filter.js100%100%100%100%
examples/wasm-emscripten
   test.filter.js100%100%100%100%
examples/wasm-simple
   test.filter.js100%100%100%100%
examples/wasm-simple-source-phase
   test.filter.js100%100%100%100%
lib
   APIPlugin.js100%100%100%100%
   AsyncDependenciesBlock.js100%100%100%100%
   AutomaticPrefetchPlugin.js100%100%100%100%
   BannerPlugin.js100%100%100%100%
   Cache.js98.21%100%100%98.21%101
   CacheFacade.js100%100%100%100%
   Chunk.js99.72%100%100%99.72%42
   ChunkGraph.js100%100%100%100%
   ChunkGroup.js100%100%100%100%
   ChunkTemplate.js100%100%100%100%
   CircularModulesPlugin.js99.35%100%100%99.35%244
   CleanPlugin.js99.12%100%100%99.12%212, 232
   CodeGenerationResults.js100%100%100%100%
   CompatibilityPlugin.js100%100%100%100%
   Compilation.js98.53%100%100%98.53%1736, 2055, 2062, 2070, 2092, 2095, 3034, 3513–3514, 3546, 4380, 4413, 4466–4467, 4471, 4476, 4492–4493, 4507–4508, 4513–4514, 5036, 5062, 5872, 5904, 5921, 5939, 5955, 5970, 5995–5996, 5998, 6333, 6338, 6344, 6347, 6354, 6366, 6368, 6372, 6390, 6405, 6439, 6495, 6519, 6635, 818–819
   Compiler.js99.56%100%100%99.56%1174–1175, 1183
   ConcatenationScope.js99.12%100%100%99.12%303
   ConditionalInitFragment.js100%100%100%100%
   ConstPlugin.js100%100%100%100%
   ContextExclusionPlugin.js100%100%100%100%
   ContextModule.js99.88%100%100%99.88%1554
   ContextModuleFactory.js97.29%100%100%97.29%289, 465, 486, 491, 532, 543, 545, 549, 558–559
   ContextReplacementPlugin.js100%100%100%100%
   DefinePlugin.js99.13%100%100%99.13%1124, 197–198, 214, 233, 307
   DependenciesBlock.js100%100%100%100%
   Dependency.js98.54%100%100%98.54%498, 545
   DependencyTemplate.js100%100%100%100%
   DependencyTemplates.js100%100%100%100%
   DotenvPlugin.js98.41%100%100%98.41%415, 428–429
   DynamicEntryPlugin.js100%100%100%100%
   EntryOptionPlugin.js100%100%100%100%
   EntryPlugin.js100%100%100%100%
   Entrypoint.js100%100%100%100%
   EnvironmentPlugin.js97.14%100%100%97.14%49
   ErrorHelpers.js100%100%100%100%
   EvalDevToolModulePlugin.js100%100%100%100%
   EvalSourceMapDevToolPlugin.js100%100%100%100%
   ExportsInfo.js99.26%100%100%99.26%415, 431, 763, 860, 878, 922, 927
   ExportsInfoApiPlugin.js100%100%100%100%
   ExternalModule.js98.76%100%100%98.76%1340, 1343, 590–594, 596, 756
   ExternalModuleFactoryPlugin.js100%100%100%100%
   ExternalsPlugin.js100%100%100%100%
   FileSystemInfo.js99.53%100%100%99.53%187, 2464–2465, 2468, 2479, 2490, 2501, 285, 3944, 3959, 3983
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.36%100%100%98.36%505, 514, 517, 521, 533
   FlagDependencyUsagePlugin.js100%100%100%100%
   FlagEntryExportAsUsedPlugin.js100%100%100%100%
   Generator.js100%100%100%100%
   HotModuleReplacementPlugin.js100%100%100%100%
   HotUpdateChunk.js100%100%100%100%
   IgnorePlugin.js100%100%100%100%
   IgnoreWarningsPlugin.js100%100%100%100%
   InitFragment.js100%100%100%100%
   JavascriptMetaInfoPlugin.js100%100%100%100%
   LazyBarrel.js100%100%100%100%
   LibraryTemplatePlugin.js100%100%100%100%
   LoaderOptionsPlugin.js100%100%100%100%
   LoaderTargetPlugin.js100%100%100%100%
   MainTemplate.js100%100%100%100%
   ManifestPlugin.js100%100%100%100%
   Module.js98.51%100%100%98.51%1317, 1322, 1382, 1396, 1458, 1467
   ModuleFactory.js100%100%100%100%
   ModuleFilenameHelpers.js98.90%100%100%98.90%111, 113
   ModuleGraph.js99.78%100%100%99.78%1180
   ModuleGraphConnection.js100%100%100%100%
   ModuleInfoHeaderPlugin.js100%100%100%100%
   ModuleNotFoundError.js100%100%100%100%
   ModuleProfile.js100%100%100%100%
   ModuleSourceTypeConstants.js100%100%100%100%
   ModuleTemplate.js100%100%100%100%
   ModuleTypeConstants.js100%100%100%100%
   MultiCompiler.js99.72%100%100%99.72%729
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js97.99%100%100%97.99%1047, 1050, 1067, 1084, 1332, 1366, 1382, 1837, 2132, 2137–2147, 29
   NormalModuleFactory.js99.01%100%100%99.01%1341, 1790, 1801, 1811, 1862–1864, 1871, 732, 744
   NormalModuleReplacementPlugin.js100%100%100%100%
   NullFactory.js100%100%100%100%
   OptimizationStages.js100%100%100%100%
   OptionsApply.js100%100%100%100%
   Parser.js100%100%100%100%
   PlatformPlugin.js100%100%100%100%
   PrefetchPlugin.js100%100%100%100%
   ProgressPlugin.js99.80%100%100%99.80%694
   ProvidePlugin.js100%100%100%100%
   RawModule.js100%100%100%100%
   RecordIdsPlugin.js100%100%100%100%
   RequestShortener.js100%100%100%100%
   ResolverFactory.js100%100%100%100%
   RuntimeGlobals.js100%100%100%100%
   RuntimeModule.js100%100%100%100%
   RuntimePlugin.js95.78%100%100%95.78%314, 380, 389, 392, 416, 434, 455–456, 479, 499–500, 536–537, 560, 573–574, 646, 659, 680, 699
   RuntimeTemplate.js99.63%100%100%99.63%350, 3688, 4288, 4300, 4305, 4307, 4312
   SelfModuleFactory.js100%100%100%100%
   SingleEntryPlugin.js100%100%100%100%
   SourceMapDevToolModuleOptionsPlugin.js100%100%100%100%
   SourceMapDevToolPlugin.js98.63%100%100%98.63%229, 233, 235, 429, 440, 899
   Stats.js100%100%100%100%
   Template.js100%100%100%100%
   TemplatedPathPlugin.js99.48%100%100%99.48%366–367
   UseStrictPlugin.js100%100%100%100%
   WarnCaseSensitiveModulesPlugin.js100%100%100%100%
   WarnDeprecatedOptionPlugin.js100%100%100%100%
   WarnNoModeSetPlugin.js100%100%100%100%
   WatchIgnorePlugin.js100%100%100%100%
   Watching.js100%100%100%100%
   WebpackError.js100%100%100%100%
   WebpackIsIncludedPlugin.js100%100%100%100%
   WebpackOptionsApply.js100%100%100%100%
   WebpackOptionsDefaulter.js100%100%100%100%
   buildChunkGraph.js99.87%100%100%99.87%375
   cli.js98.63%100%100%98.63%10, 117, 547, 579, 629, 903
   index.js99.73%100%100%99.73%184
   validateSchema.js94.67%100%100%94.67%100, 87, 89, 98
   webpack.js97.12%100%100%97.12%10, 274, 296, 298
lib/asset
   AssetBytesGenerator.js100%100%100%100%
   AssetBytesParser.js100%100%100%100%
   AssetGenerator.js100%100%100%100%
   AssetModule.js100%100%100%100%
   AssetModulesPlugin.js98.15%100%100%98.15%338, 362, 365, 495, 57, 62
   AssetParser.js100%100%100%100%
   AssetSourceGenerator.js100%100%100%100%
   AssetSourceParser.js100%100%100%100%
   RawDataUrlModule.js100%100%100%100%
   WebManifestGenerator.js100%100%100%100%
   WebManifestParser.js100%100%100%100%
lib/async-modules
   AsyncModuleHelpers.js100%100%100%100%
   AwaitDependenciesInitFragment.js100%100%100%100%
   InferAsyncModulesPlugin.js100%100%100%100%
   isGeneratorLowered.js100%100%100%100%
lib/bun
   BunTargetPlugin.js100%100%100%100%
lib/cache
   AddBuildDependenciesPlugin.js100%100%100%100%
   AddManagedPathsPlugin.js100%100%100%100%
   IdleFileCachePlugin.js97.92%100%100%97.92%75, 87, 95
   MemoryCachePlugin.js92%100%100%92%33, 42
   MemoryWithGcCachePlugin.js93.42%100%100%93.42%107, 121–122, 131, 89
   PackFileCacheStrategy.js96.52%100%100%96.52%1317, 1417, 1421, 1483, 1719, 1803, 1826, 1858, 682, 701, 711–713,

@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.09%. Comparing base (9f6a084) to head (8bb397e).
⚠️ Report is 6 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #21884   +/-   ##
=======================================
  Coverage   95.08%   95.09%           
=======================================
  Files         702      702           
  Lines       90697    90750   +53     
  Branches    27368    27395   +27     
=======================================
+ Hits        86242    86299   +57     
+ Misses       4455     4451    -4     
Flag Coverage Δ
css-parsing 24.77% <0.00%> (-0.02%) ⬇️
html5lib 29.90% <0.00%> (-0.02%) ⬇️
integration 88.64% <100.00%> (+0.01%) ⬆️
syntax-equivalence 79.77% <ø> (ø)
test262 44.53% <100.00%> (+0.03%) ⬆️
unit 56.55% <0.00%> (-0.04%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@hai-x
hai-x marked this pull request as ready for review August 31, 2026 18:52
@github-actions

Copy link
Copy Markdown
Contributor

Generated code size

Comparing 8bb397e merged into c961f61 against c961f61. Merging this pull request changes the size of 4 asset(s) and adds 3 new asset(s).

Changed New Deleted Unchanged Gzip change Raw change Gzip new/gone Raw new/gone
Cases 3 1 0 1970 🟢 ↓ -1.78 KiB 🟢 ↓ -6.36 KiB +2.69 KiB +8.48 KiB
Assets 4 3 0 7224 🟢 ↓ -1.78 KiB 🟢 ↓ -6.36 KiB +2.69 KiB +8.48 KiB
Runtimes 4 1 0 2274

Gzip change decides — it is what a user downloads, and a re-encoding can cut raw bytes while costing wire bytes. Raw change is the tiebreak: it is what the generator wrote, so it is what has to be decompressed and parsed. Both are over assets both runs emit; bytes an added or deleted case brings with it are counted apart, under new/gone. Brotli and zstd are per asset in the table below.

4 asset(s) changed size
Asset Before After Change Gzip (9) Brotli (11) Zstd (19)
🟢 ↓ concatenate-modules/commonjs-require-call-sites bundle0.js 11.14 KiB 8.53 KiB -2.61 KiB (-23.44%) -711 B (-23.37%) -633 B (-23.72%) -698 B (-23.31%)
🟢 ↓ concatenate-modules/commonjs-module-bailouts bundle0.js 10.52 KiB 7.96 KiB -2.57 KiB (-24.38%) -692 B (-23.94%) -624 B (-24.39%) -677 B (-23.76%)
🟢 ↓ library/1-use-library 29/bundle29.js 2.68 KiB 2.08 KiB -607 B (-22.15%) -211 B (-19.11%) -194 B (-19.42%) -209 B (-19.10%)
🟢 ↓ library/1-use-library 33/bundle33.js 2.85 KiB 2.25 KiB -607 B (-20.82%) -208 B (-17.87%) -195 B (-18.62%) -203 B (-17.70%)
3 asset(s) this pull request adds
Asset Raw Gzip (9) Brotli (11) Zstd (19)
concatenate-modules/issue-21882 main.js 8.12 KiB 2.41 KiB 2.08 KiB 2.38 KiB
concatenate-modules/issue-21882 split.js 331 B 223 B 190 B 211 B
concatenate-modules/issue-21882 [hash].svg 42 B 62 B 46 B 51 B
4 runtime(s) changed which runtime modules they carry
Runtime Modules Added Removed
🟢 ↓ concatenate-modules/commonjs-module-bailouts main 5 → 1 create fake namespace object, define property getters, hasOwnProperty shorthand, make namespace object
🟢 ↓ concatenate-modules/commonjs-require-call-sites main 5 → 1 create fake namespace object, define property getters, hasOwnProperty shorthand, make namespace object
🟢 ↓ library/1-use-library 29/main 6 → 4 create fake namespace object, make namespace object
🟢 ↓ library/1-use-library 33/main 6 → 4 create fake namespace object, make namespace object
1 runtime(s) this pull request adds or no longer builds
Runtime Modules
concatenate-modules/issue-21882 main 5

Built test/configCases with the defaults a user gets: 1974 case(s), 7231 asset(s), 76 emitted nothing.

@codspeed-hq

codspeed-hq Bot commented Aug 31, 2026

Copy link
Copy Markdown

Merging this PR will regress 1 benchmark

⚠️ 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

⚡ 2 improved benchmarks
❌ 1 regressed benchmark
✅ 325 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory benchmark "many-modules-esm", scenario '{"name":"mode-production","mode":"production"}' 9.2 MB 11.5 MB -20.39%
Memory benchmark "asset-modules-source", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 1,368.4 KB 656 KB ×2.1
Memory benchmark "wasm-modules-sync", scenario '{"name":"mode-production","mode":"production"}' 9.3 MB 7.3 MB +26.1%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing fix/concat-external-require-interop (8bb397e) with main (c961f61)

Open in CodSpeed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: optimization Tree-shaking, splitChunks, concatenation, ids (lib/optimize, lib/ids)

Projects

None yet

2 participants

Sponsor
SponsoredKunjungi sekarang
Promo