feat: add "module-sync" to default conditionNames#20933
Conversation
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.
🦋 Changeset detectedLatest commit: 5c45414 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
|
This PR is packaged and the instant preview is available (ac6d497). Install it locally:
npm i -D webpack@https://pkg.pr.new/webpack@ac6d497
yarn add -D webpack@https://pkg.pr.new/webpack@ac6d497
pnpm add -D webpack@https://pkg.pr.new/webpack@ac6d497 |
Codecov Report✅ All modified and coverable lines are covered by tests. 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
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
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 resolverconditionNamesingetResolveDefaults(and inherited dependency-type defaults like worker). - Add
"module-sync"toFileSystemInfobuild-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.
| { | ||
| 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"] | ||
| } | ||
| ] | ||
| } | ||
| }, |
There was a problem hiding this comment.
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
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.
Types CoverageCoverage after merging claude/add-module-sync-support-zRh9K into main will be
Coverage Report
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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
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
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 inFileSystemInfo.