Skip to content

feat: add "module-sync" to default conditionNames#20933

Merged
alexander-akait merged 7 commits into
mainfrom
claude/add-module-sync-support-zRh9K
May 8, 2026
Merged

feat: add "module-sync" to default conditionNames#20933
alexander-akait merged 7 commits into
mainfrom
claude/add-module-sync-support-zRh9K

Conversation

@alexander-akait

Copy link
Copy Markdown
Member

Aligns webpack's default resolver conditions with Node.js, which
exposes the "module-sync" community condition for synchronously-
loadable ESM. Added in cjsDeps/esmDeps (and thus worker via spread)
in getResolveDefaults, plus the build-dependency resolvers in
FileSystemInfo.

Aligns webpack's default resolver conditions with Node.js, which
exposes the "module-sync" community condition for synchronously-
loadable ESM. Added in cjsDeps/esmDeps (and thus worker via spread)
in `getResolveDefaults`, plus the build-dependency resolvers in
`FileSystemInfo`.
Adds resolving/module-sync test case verifying that:
- module-sync acts as a fallback when import/require are absent
- module-sync wins when listed before import/require in package.json
- import/require still take priority when listed before module-sync

Mirrors Node.js's "module-sync" condition semantics — both import
(ESM) and require (CJS) resolutions activate the condition.
Augments the resolving/module-sync test case to compare webpack's
bundled require/import results against Node.js's actual require() and
dynamic import() of the same fixtures. The reference values come from a
child Node.js process — Jest patches Module.createRequire in a way that
drops "module-sync" from the active condition set, so an in-process
reference would not match Node.js behavior.

Adds a test.filter.js that probes the running Node.js for "module-sync"
support and skips the case on older versions (<22.10) where Node.js does
not activate the condition by default.
jest-environment-node's customExportConditions defaults to
["node", "node-addons"], so jest-runtime resolves package.json
"exports" without the "module-sync" community condition active. Add
"module-sync" to the test environment options so an in-process
Module.createRequire() and dynamic import() inside test.config.js mirror
real Node.js resolution. Drops the child-process workaround in the
resolving/module-sync test case in favor of direct require/import.
Copilot AI review requested due to automatic review settings May 8, 2026 10:18
@changeset-bot

changeset-bot Bot commented May 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5c45414

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

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

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 May 8, 2026

Copy link
Copy Markdown
Contributor

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

Install it locally:

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

@codecov

codecov Bot commented May 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.37%. Comparing base (4e45617) to head (5c45414).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #20933      +/-   ##
==========================================
+ Coverage   91.34%   91.37%   +0.02%     
==========================================
  Files         566      568       +2     
  Lines       56130    56515     +385     
  Branches    14904    15016     +112     
==========================================
+ Hits        51274    51639     +365     
- Misses       4856     4876      +20     
Flag Coverage Δ
integration 90.31% <100.00%> (+0.03%) ⬆️
test262 45.57% <100.00%> (-0.04%) ⬇️
unit 36.01% <100.00%> (-0.03%) ⬇️

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

☔ View full report in Codecov by Sentry.
📢 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.

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 updates webpack’s default resolver conditionNames to include Node.js’s "module-sync" export condition, aiming to better align package exports resolution behavior with modern Node.js for synchronously-loadable ESM. It also adds coverage to validate the behavior and ensures the test runner environment resolves exports using the same condition set.

Changes:

  • Add "module-sync" to default resolver conditionNames in getResolveDefaults (and inherited dependency-type defaults like worker).
  • Add "module-sync" to FileSystemInfo build-dependency resolvers’ conditionNames.
  • Add a new resolving test case/fixtures for "module-sync", update defaults snapshots, and adjust Jest/ESLint config to support the new test setup.

Reviewed changes

Copilot reviewed 8 out of 22 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
lib/config/defaults.js Adds "module-sync" to default CJS/ESM dependency resolver condition names.
lib/FileSystemInfo.js Adds "module-sync" to build dependency resolution conditions (CJS + ESM).
test/Defaults.unittest.js Updates snapshots to reflect the new default conditionNames ordering.
test/cases/resolving/module-sync/test.filter.js Skips the resolving case when the running Node doesn’t activate "module-sync" for require().
test/cases/resolving/module-sync/test.config.js Injects Node require/dynamic import() helpers into the test runtime for comparison.
test/cases/resolving/module-sync/index.js Verifies webpack resolution matches Node behavior across different exports condition orderings.
test/cases/resolving/module-sync/node_modules/** Adds fixture packages exercising "module-sync" vs import/require/default branches.
jest.config.js Adds testEnvironmentOptions.customExportConditions to include "module-sync" for Jest’s resolver.
eslint.config.mjs Adds an override allowing dynamic import() syntax in test.config.js under test/cases/**.
.changeset/module-sync-condition.md Declares a minor release note for the resolver default change.

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

Comment thread eslint.config.mjs Outdated
Comment on lines +116 to +130
{
files: ["test/cases/**/test.config.js"],
// Allow to use `dynamic` import for routing through Node.js's ESM resolver
languageOptions: {
ecmaVersion: 2020
},
rules: {
"n/no-unsupported-features/es-syntax": [
"error",
{
ignores: ["dynamic-import"]
}
]
}
},

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch — the ESLint override has been removed entirely in 7b7525a. Setting customExportConditions to include "module-sync" globally turned out to break unrelated tests (e.g. configCases/module/custom-javascript-parser failing with "Must use import to load ES Module" because real deps like meriyah/file-type point their module-sync exports at .mjs files that Jest's CJS runtime can't load). Reverted both the jest config change and the ESLint override, and went back to the isolated child-process probe in test/cases/resolving/module-sync/test.config.js — no dynamic-import in test configs, no global lint relaxation.


Generated by Claude Code

@codspeed-hq

codspeed-hq Bot commented May 8, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 56.2%

⚡ 5 improved benchmarks
❌ 3 regressed benchmarks
✅ 136 untouched benchmarks
⏩ 72 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory benchmark "devtool-eval-source-map", scenario '{"name":"mode-production","mode":"production"}' 6.3 MB 7.8 MB -20.17%
Memory benchmark "side-effects-reexport", scenario '{"name":"mode-development","mode":"development"}' 5.1 MB 4 MB +27.74%
Memory benchmark "many-modules-esm", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 224.2 KB 164.9 KB +35.99%
Memory benchmark "asset-modules-inline", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 223.5 KB 292.7 KB -23.63%
Memory benchmark "side-effects-reexport", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 1,550.1 KB 848.2 KB +82.75%
Memory benchmark "many-chunks-commonjs", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 921.3 KB 459 KB ×2
Memory benchmark "asset-modules-source", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 160.3 KB 366 KB -56.2%
Memory benchmark "future-defaults", scenario '{"name":"mode-production","mode":"production"}' 11.1 MB 7.6 MB +46.59%

Comparing claude/add-module-sync-support-zRh9K (5c45414) with main (26e549a)

Open in CodSpeed

Footnotes

  1. 72 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.

Setting jest-environment-node's customExportConditions to include
"module-sync" affected resolution of every dependency in the test suite.
Several real packages (e.g. meriyah, file-type) point their
"module-sync" exports at .mjs files, and Jest's CJS runtime cannot load
ESM via require() — so "Must use import to load ES Module" errors
surfaced in the configCases/module/custom-javascript-parser case (and
others). Drop the global jest config change and the matching ESLint
override, and go back to the isolated child-process probe in the
fixture's test.config.js / test.filter.js, which keeps the comparison
truly out-of-process and confined to this one test case.
Use worker_threads instead of child_process / execFileSync to capture
real Node.js resolution. A worker thread runs in a fresh Node.js
context that bypasses Jest's runtime patches (Jest's CJS resolver omits
the "module-sync" condition), without spawning an external process.

* node-resolve.worker.mjs is the worker entrypoint — uses createRequire
  for require() resolution and dynamic import() for ESM resolution, both
  with the "module-sync" condition active.
* test.config.js exposes async nodeRequire / nodeImport helpers backed by
  a single worker run, started when the config loads.
* test.filter.js probes for module-sync support with a sync worker
  (Atomics.wait + a sync require — no dynamic import, which would
  deadlock against a parked main thread).
Every runtime path tried — Module.createRequire, dynamic import(),
__non_webpack_require__, webpackIgnore — goes through Jest's VM
loader, which does not activate the "module-sync" condition; the only
ways around it were a child process or a worker thread. Drop the
dynamic comparison and assert against the values Node.js v22.10+
documents for each fixture, with comments explaining why each
expectation matches Node.js's "exports" resolution. This is a
compile-time test of webpack's resolver against the documented
spec; a separate Node.js-only integration test would be needed to
verify the runtime side.
@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging claude/add-module-sync-support-zRh9K into main will be
98.93%
Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
bin
   webpack.js98.77%100%100%98.77%91
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.js91.30%100%100%91.30%140, 142–143, 145, 147, 153–154, 161, 168, 90
examples/markdown
   webpack.config.mjs100%100%100%100%
examples/typescript
   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-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%37
   ChunkGraph.js100%100%100%100%
   ChunkGroup.js100%100%100%100%
   ChunkTemplate.js100%100%100%100%
   CleanPlugin.js98.72%100%100%98.72%206, 226, 382
   CodeGenerationResults.js100%100%100%100%
   CompatibilityPlugin.js100%100%100%100%
   Compilation.js98.55%100%100%98.55%1554, 1850, 1857, 1865, 1887, 2783, 3208, 3870, 3899, 3952–3953, 3957, 3962, 3978–3979, 3993–3994, 3999–4000, 4477, 4503, 493, 498, 5211, 5292, 5307, 5332–5333, 5335, 5659, 5664, 5670, 5673, 5685, 5687, 5691, 5707, 5722, 5754, 5808, 5832, 5946, 712–713
   Compiler.js99.55%100%100%99.55%1116–1117, 1125
   ConcatenationScope.js98.59%100%100%98.59%189
   ConditionalInitFragment.js100%100%100%100%
   ConstPlugin.js100%100%100%100%
   ContextExclusionPlugin.js100%100%100%100%
   ContextModule.js100%100%100%100%
   ContextModuleFactory.js97.75%100%100%97.75%258, 393, 418, 443, 447, 458
   ContextReplacementPlugin.js100%100%100%100%
   DefinePlugin.js98.92%100%100%98.92%158–159, 175, 194, 268
   DependenciesBlock.js100%100%100%100%
   Dependency.js98.20%100%100%98.20%379, 425
   DependencyTemplate.js100%100%100%100%
   DependencyTemplates.js100%100%100%100%
   DotenvPlugin.js97.88%100%100%97.88%237, 378, 391–392
   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.js100%100%100%100%
   ExportsInfoApiPlugin.js100%100%100%100%
   ExternalModule.js98.89%100%100%98.89%399–403, 542
   ExternalModuleFactoryPlugin.js100%100%100%100%
   ExternalsPlugin.js100%100%100%100%
   FileSystemInfo.js99.50%100%100%99.50%182, 2252–2253, 2256, 2267, 2278, 2289, 278, 3694, 3709, 3733
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.74%100%100%98.74%399, 401, 405
   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%
   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.50%100%100%98.50%1304, 1309, 1370, 1384, 1446, 1455
   ModuleFactory.js100%100%100%100%
   ModuleFilenameHelpers.js98.85%100%100%98.85%106, 108
   ModuleGraph.js99.73%100%100%99.73%1004
   ModuleGraphConnection.js100%100%100%100%
   ModuleInfoHeaderPlugin.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.69%100%100%99.69%645
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js97.78%100%100%97.78%1020, 1036, 1123, 1774, 1779–1789, 708, 711, 728, 745, 986
   NormalModuleFactory.js99.47%100%100%99.47%1074, 1383, 473, 485
   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.js98.85%100%100%98.85%519–520, 525, 527, 591
   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.js100%100%100%100%
   RuntimeTemplate.js100%100%100%100%
   SelfModuleFactory.js100%100%100%100%
   SingleEntryPlugin.js100%100%100%100%
   SourceMapDevToolModuleOptionsPlugin.js100%100%100%100%
   SourceMapDevToolPlugin.js99.16%100%100%99.16%267–268, 610
   Stats.js100%100%100%100%
   Template.js100%100%100%100%
   TemplatedPathPlugin.js98.86%100%100%98.86%134–135
   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%325
   cli.js98.71%100%100%98.71%117, 469, 501, 543, 813
   index.js100%100%100%100%
   validateSchema.js94.67%100%100%94.67%100, 87, 89, 98
   webpack.js97.22%100%100%97.22%196, 218, 220
lib/asset
   AssetBytesGenerator.js100%100%100%100%
   AssetBytesParser.js100%100%100%100%
   AssetGenerator.js100%100%100%100%
   AssetModulesPlugin.js97.77%100%100%97.77%285, 309, 312, 364, 40
   AssetParser.js100%100%100%100%
   AssetSourceGenerator.js100%100%100%100%
   AssetSourceParser.js100%100%100%100%
   RawDataUrlModule.js100%100%100%100%
lib/async-modules
   AsyncModuleHelpers.js100%100%100%100%
   AwaitDependenciesInitFragment.js100%100%100%100%
   InferAsyncModulesPlugin.js100%100%100%100%
lib/cache
   AddBuildDependenciesPlugin.js100%100%100%100%
   AddManagedPathsPlugin.js100%100%100%100%
   IdleFileCachePlugin.js97.92%100%100%97.92%71, 83, 91
   MemoryCachePlugin.js95.83%100%100%95.83%33
   MemoryWithGcCachePlugin.js93.15%100%100%93.15%106, 113–114, 122, 89
   PackFileCacheStrategy.js96.40%100%100%96.40%1250, 1350, 1354, 1416, 628, 647, 657–659, 661, 677–678, 683, 686, 688, 693, 698, 722, 728, 762, 768, 774, 779, 790, 799, 804–805, 807, 824, 830–831, 833
   ResolverCachePlugin.js100%100%100%100%
   getLazyHashedEtag.js100%100%100%100%
   mergeEtags.js100%100%100%100%
lib/config
   browserslistTargetHandler.js100%100%100%100%
   defaults.js99.15%100%100%99.15%1327–1329, 1337, 271, 274, 279, 283, 472
   normalization.js99%100%100%99%191–192, 258, 273
   target.js100%100%100%100%
lib/container
   ContainerEntryDependency.js100%100%100%100%
   ContainerEntryModule.js100%100%100%100%
   ContainerEntryModuleFactory.js100%100%100%100%
   ContainerExposedDependency.js100%100%100%100%
   ContainerPlugin.js100%100%100%100%
   ContainerReferencePlugin.js100%100%100%100%
   FallbackDependency.js100%100%100%100%
   FallbackItemDependency.js100%100%100%100%
   FallbackModule.js100%100%100%100%
   FallbackModuleFactory.js100%100%100%100%
   HoistContainerReferencesPlugin.js100%100%100%100%
   ModuleFederationPlugin.js100%100%100%100%
   RemoteModule.js100%100%100%100%
   RemoteRuntimeModule.js100%100%100%100%
   

@alexander-akait alexander-akait merged commit ac6d497 into main May 8, 2026
60 of 61 checks passed
@alexander-akait alexander-akait deleted the claude/add-module-sync-support-zRh9K branch May 8, 2026 17:14
aryanraj45 pushed a commit to aryanraj45/webpack that referenced this pull request May 8, 2026
bjohansebas added a commit to webpack/webpack.js.org that referenced this pull request May 17, 2026
Webpack 5.107 adds "module-sync" to the default conditionNames for ESM,
CJS, AMD, worker, wasm, and build-dependency resolvers, aligning with
Node.js. This updates the per-dependency conditionNames defaults table
in resolve.mdx and notes the alignment with Node.js's module-sync
community condition.

Refs: webpack/webpack#20933
alexander-akait pushed a commit to webpack/webpack.js.org that referenced this pull request May 18, 2026
Webpack 5.107 adds "module-sync" to the default conditionNames for ESM,
CJS, AMD, worker, wasm, and build-dependency resolvers, aligning with
Node.js. This updates the per-dependency conditionNames defaults table
in resolve.mdx and notes the alignment with Node.js's module-sync
community condition.

Refs: webpack/webpack#20933
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