Skip to content

perf: guard isDeferred() behind experiments.deferImport in ConcatenatedModule#21096

Merged
alexander-akait merged 2 commits into
webpack:mainfrom
shashank-u03:fix/concatenated-module-defer-import-guard
Jun 4, 2026
Merged

perf: guard isDeferred() behind experiments.deferImport in ConcatenatedModule#21096
alexander-akait merged 2 commits into
webpack:mainfrom
shashank-u03:fix/concatenated-module-defer-import-guard

Conversation

@shashank-u03

@shashank-u03 shashank-u03 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary

In large builds with many external modules (for example, Module Federation remotes and CDN externals), ConcatenatedModule unconditionally calls moduleGraph.isDeferred() for every type: "external" entry during code generation and hash generation.

moduleGraph.isDeferred() walks all incoming connections of a module. When experiments.deferImport is disabled (the default), the result is guaranteed to be false, making these traversals unnecessary. In large applications this can result in a significant amount of redundant work.

ModuleConcatenationPlugin already avoids this overhead by guarding its isDeferred() check behind deferEnabled:

// ModuleConcatenationPlugin.js
if (deferEnabled && moduleGraph.isDeferred(module)) { ... }

The same guard was missing in ConcatenatedModule._getModulesWithInfo() and ConcatenatedModule.updateHash().

This change adds the missing guard, avoiding unnecessary graph traversals when deferImport is disabled while preserving the existing behavior when it is enabled.

In a real-world Next.js application using Module Federation with approximately 10 remotes, build profiling attributed roughly 11 minutes of build time to these redundant traversals.

Before CPU Profile
image

After CPU Profile
image

What kind of change does this PR introduce?

perf

This change does not alter functionality. It only skips work that is provably unnecessary when experiments.deferImport is disabled.

Did you add tests for your changes?

No additional tests were added.

The behavior when experiments.deferImport: true remains unchanged. This change only replaces a computed false result with an explicit false when deferImport is disabled.

Does this PR introduce a breaking change?

No runtime behavior changes are introduced.

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

No documentation changes are required.

Use of AI

partial

@changeset-bot

changeset-bot Bot commented Jun 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 93041a9

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

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

👋 Hi there! This PR was automatically flagged and closed by our quality checks.

If you believe this was a mistake, please review our contributing guidelines
and leave a comment explaining why this is a mistake.

@github-actions github-actions Bot closed this Jun 4, 2026
@shashank-u03

Copy link
Copy Markdown
Contributor Author

Hi, I believe this was flagged in error. This is a genuine performance fix — not a spam or low-quality contribution.

The PR adds a missing experiments.deferImport guard in ConcatenatedModule that already exists in ModuleConcatenationPlugin. Without it, moduleGraph.isDeferred() performs a full incoming-connections traversal for every external module in every ConcatenatedModule instance, even when deferImport is false (the default for all webpack projects). In our large Module Federation monorepo this caused an ~11 minute build time regression.

The CLA is signed and a changeset is included. Happy to address any feedback from the maintainers.

@alexander-akait

Copy link
Copy Markdown
Member

Please stop SPAM, if you think it was by mistake, just a wait an answer

@codecov

codecov Bot commented Jun 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.81%. Comparing base (2a7c5ca) to head (93041a9).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #21096      +/-   ##
==========================================
+ Coverage   91.67%   91.81%   +0.14%     
==========================================
  Files         581      581              
  Lines       61163    61168       +5     
  Branches    16691    16696       +5     
==========================================
+ Hits        56069    56161      +92     
+ Misses       5094     5007      -87     
Flag Coverage Δ
integration 89.59% <100.00%> (+0.01%) ⬆️
test262 45.31% <83.33%> (+<0.01%) ⬆️
unit 38.54% <0.00%> (+0.86%) ⬆️

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.

@codspeed-hq

codspeed-hq Bot commented Jun 4, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 72 untouched benchmarks
🗄️ 72 archived benchmarks run1


Comparing shashank-u03:fix/concatenated-module-defer-import-guard (93041a9) with main (1ff842a)

Open in CodSpeed

Footnotes

  1. 72 benchmarks were run, but are now archived. If they were deleted in another branch, consider rebasing to remove them from the report. Instead if they were added back, click here to restore them.

@alexander-akait alexander-akait merged commit 657d57b into webpack:main Jun 4, 2026
59 checks passed
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

This PR is packaged and the instant preview is available (657d57b).

Install it locally:

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

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