Skip to content

fix: resolve aliases pointing at a package directory ending in .js - #21542

Merged
alexander-akait merged 3 commits into
mainfrom
fix/typescript-auto-resolve-defaults
Jul 28, 2026
Merged

alexander-akait merged 3 commits into
mainfrom
fix/typescript-auto-resolve-defaults

Conversation

@alexander-akait

@alexander-akait alexander-akait commented Jul 28, 2026

Copy link
Copy Markdown
Member

Summary

experiments.typescript: "auto" only checks that Node.js can strip types and that no TS loader is registered — never whether the project contains any TypeScript — so since 5.109.0 every project on Node.js >= 22.6 silently got TypeScript resolution semantics: .ts ahead of .js, tsconfig paths, the .js -> .ts extension alias, and the typescript exports condition. Those now require an explicit opt-in, and .ts stays a low-priority extension otherwise, matching how the css/html "auto" defaults already avoid shadowing x.js. Fixes #21541.

What kind of change does this PR introduce?

fix

Did you add tests for your changes?

Yes — test/configCases/typescript/experiments-auto-resolve-defaults covers all three resolution changes, and test/Defaults.unittest.js asserts the auto vs. explicit vs. futureDefaults resolve options.

Does this PR introduce a breaking change?

No — it restores the pre-5.109.0 resolution behavior for projects that never opted into TypeScript; experiments.typescript: true is unchanged.

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

experiments.typescript docs should note that tsconfig paths, the .js -> .ts extension alias, the typescript exports condition and .ts-before-.js ordering need typescript: true, not the "auto" default.

Use of AI

AI (Claude Code) was used to trace the regression through the resolve defaults, probe the other auto-enabled resolution changes, and draft the fix and tests; the diagnosis and the final diff were reviewed by a human before submitting.


Generated by Claude Code


Note

Low Risk
Dependency-only resolver patch plus an integration test; no webpack core logic changes beyond the lockfile bump.

Overview
Fixes a regression where resolve.alias targets (and similar paths) could fail when the real package folder name ends with .js (e.g. node_modules/pkg.js), especially when resolve.extensionAlias maps .js.ts.

The change bumps enhanced-resolve from ^5.24.2 to ^5.24.4, which carries the resolver fix; webpack itself has no resolver logic changes in this diff. A new config case alias-to-package-directory asserts that require("vendor/pkg.js") resolves through an alias to node_modules with the same .js.ts extensionAlias shape TypeScript experiments use, without treating the package directory as an extension rewrite target.

Reviewed by Cursor Bugbot for commit 68a0820. Bugbot is set up for automated code reviews on this repo. Configure here.

@changeset-bot

changeset-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 68a0820

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 Jul 28, 2026

Copy link
Copy Markdown
Contributor

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

Install it locally:

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

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.82%. Comparing base (9cdcc57) to head (68a0820).

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #21542   +/-   ##
=======================================
  Coverage   93.82%   93.82%           
=======================================
  Files         620      620           
  Lines       73591    73591           
  Branches    21273    21273           
=======================================
  Hits        69046    69046           
  Misses       4545     4545           
Flag Coverage Δ
css-parsing 25.59% <ø> (ø)
html5lib 27.02% <ø> (ø)
integration 89.60% <ø> (ø)
test262 43.35% <ø> (+0.02%) ⬆️
unit 47.19% <ø> (ø)

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

codspeed Bot commented Jul 28, 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

⚡ 1 improved benchmark
❌ 1 regressed benchmark
✅ 214 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory benchmark "many-chunks-esm", scenario '{"name":"mode-production","mode":"production"}' 7.3 MB 9.3 MB -21.5%
Memory benchmark "devtool-eval", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 3.1 MB 1.3 MB ×2.4

Tip

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


Comparing fix/typescript-auto-resolve-defaults (68a0820) with main (9cdcc57)

Open in CodSpeed

alexander-akait added a commit to webpack/enhanced-resolve that referenced this pull request Jul 28, 2026
…ts own extension (#641)

<!-- Thanks for submitting a pull request! Please provide enough
information so that others can review your pull request. -->

**Summary**

`ExtensionAliasPlugin` marks every candidate `fullySpecified: true` and
then refuses to fall back, so a request ending in an aliased extension
can only ever resolve as an exact file — never as a directory or via
`package.json#main`. With the source extension listed among its own
aliases (`{ ".js": [".js", ".ts"] }` — the documented TypeScript recipe,
and what `experiments.typescript` sets in webpack) that entry is meant
to keep the original request valid, but it is tried fully specified too,
so any package or directory whose name ends in `.js` becomes
unreachable. This makes the identity entry mean what it says: after the
fully specified candidates fail, fall through to normal resolution. A
mapping that drops the source extension (`{ ".js": [".ts"] }`, `{
".mjs": ".mts" }`) stays strict.

Refs webpack/webpack#21541. That regression is fixed on the webpack side
in webpack/webpack#21542 and does not need this; this closes the same
failure for projects that genuinely enable TypeScript today, and ahead
of TypeScript becoming a default.

<!-- Explain the **motivation** for making this change. What existing
problem does the pull request solve? -->
<!-- Try to link to an open issue for more information. -->
<!-- Any other information related to changes. -->

<!-- In addition to that please answer these questions: -->

**What kind of change does this PR introduce?**

fix

<!-- E.g. a fix, feat, refactor, perf, test, chore, ci, build, style,
revert, docs or describe it if you did not find a suitable kind of
change. -->

**Did you add tests for your changes?**

Yes — three cases in `test/extension-alias.test.js` (directory named
`dir3.js`, an aliased absolute path to a `pkg.js` package, and a strict
mapping that must keep failing) plus the matching fixtures.

<!-- Please note: in most cases, if you change the code, we will not
merge your changes unless you add tests. -->

**Does this PR introduce a breaking change?**

No — it only turns previously failing resolutions into successes;
exact-file candidates are still tried first, so nothing that resolves
today resolves differently.

<!-- If this PR introduces a breaking change, please describe the impact
and a migration path for existing applications. -->

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

`extensionAlias` docs should say that listing an extension among its own
aliases keeps the original request resolvable in its normal form, while
omitting it makes the mapping strict.

<!-- List all the information that needs to be added to the
documentation after merge that has already been documented in this PR.
-->

**Use of AI**

AI (Claude Code) was used to trace the failure, draft the fix and tests,
and verify them; the diagnosis and the final diff were reviewed by a
human before submitting.

<!-- If you have used AI, please state so here. Explain how you used it.
Make sure to read our AI policy
(https://github.com/webpack/governance/blob/main/AI_POLICY.md) or your
Pull Request may be closed due to irresponsible use of AI. -->
@alexander-akait
alexander-akait force-pushed the fix/typescript-auto-resolve-defaults branch from f11b2ca to a8b8955 Compare July 28, 2026 15:34
@alexander-akait alexander-akait changed the title fix: don't change resolution when experiments.typescript auto-enables fix: resolve aliases pointing at a package directory ending in .js Jul 28, 2026

Copy link
Copy Markdown
Member Author

CI is red on every job for one reason, and it is expected:

error Couldn't find any versions for "enhanced-resolve" that matches "^5.24.4"

yarn --frozen-lockfile fails before anything runs, because this PR bumps the range to the release that carries webpack/enhanced-resolve#641 and that version is not published yet (npm latest is still 5.24.3).

Unblocking is a release, not a code change. Once enhanced-resolve 5.24.4 is out, yarn.lock needs regenerating in this branch and CI should go green. The regression test was verified locally against both sides: it fails on 5.24.3 with the issue's exact Can't resolve 'vendor/pkg.js' error and passes with the fix applied.


Generated by Claude Code

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a8b8955. Configure here.

Comment thread package.json
The `.js` -> `.ts` extensionAlias that `experiments.typescript` installs made
`ExtensionAliasPlugin` resolve such a request as an exact file only, so a
package directory named `pkg.js` became unreachable. Fixed in enhanced-resolve
(webpack/enhanced-resolve#641); take the release and add a regression test.
Relying on the `experiments.typescript` "auto" default made the case a no-op
below Node.js 22.6, where the alias is never installed.
@alexander-akait
alexander-akait force-pushed the fix/typescript-auto-resolve-defaults branch from 0080355 to 68a0820 Compare July 28, 2026 17:31
@github-actions

Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging fix/typescript-auto-resolve-defaults into main will be
99.32%
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%39
   ChunkGraph.js100%100%100%100%
   ChunkGroup.js100%100%100%100%
   ChunkTemplate.js100%100%100%100%
   CircularModulesPlugin.js98.81%100%100%98.81%136
   CleanPlugin.js99.13%100%100%99.13%214, 234
   CodeGenerationResults.js100%100%100%100%
   CompatibilityPlugin.js100%100%100%100%
   Compilation.js98.42%100%100%98.42%1648, 1967, 1974, 1982, 2004, 2007, 2946, 3425–3426, 3458, 4162, 4192, 4245–4246, 4250, 4255, 4271–4272, 4286–4287, 4292–4293, 4773, 4799, 527, 532, 5607, 5639, 5656, 5672, 5688, 5703, 5728–5729, 5731, 6061, 6066, 6072, 6075, 6082, 6094, 6096, 6100, 6116, 6131, 6163, 6217, 6241, 6356, 778–779
   Compiler.js99.56%100%100%99.56%1159–1160, 1168
   ConcatenationScope.js98.65%100%100%98.65%195
   ConditionalInitFragment.js100%100%100%100%
   ConstPlugin.js100%100%100%100%
   ContextExclusionPlugin.js100%100%100%100%
   ContextModule.js99.88%100%100%99.88%1461
   ContextModuleFactory.js97.20%100%100%97.20%266, 435, 456, 461, 501, 512, 514, 518, 527–528
   ContextReplacementPlugin.js100%100%100%100%
   DefinePlugin.js99.08%100%100%99.08%1080, 176–177, 193, 212, 286
   DependenciesBlock.js100%100%100%100%
   Dependency.js98.51%100%100%98.51%479, 525
   DependencyTemplate.js100%100%100%100%
   DependencyTemplates.js100%100%100%100%
   DotenvPlugin.js98.41%100%100%98.41%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.65%100%100%98.65%1202, 1205, 514–518, 520, 666
   ExternalModuleFactoryPlugin.js100%100%100%100%
   ExternalsPlugin.js100%100%100%100%
   FileSystemInfo.js99.16%100%100%99.16%1267, 1269–1274, 1281, 1284, 182, 2502–2503, 2506, 2517, 2528, 2539, 280, 3976, 3991, 4015
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.21%100%100%98.21%448, 457, 460, 464, 476
   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.50%100%100%98.50%1288, 1293, 1353, 1367, 1429, 1438
   ModuleFactory.js100%100%100%100%
   ModuleFilenameHelpers.js98.89%100%100%98.89%106, 108
   ModuleGraph.js99.73%100%100%99.73%1005
   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.70%100%100%99.70%663
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js97.96%100%100%97.96%1000, 1017, 1034, 1282, 1316, 1332, 1779, 2076, 2081–2091, 34, 997
   NormalModuleFactory.js98.72%100%100%98.72%1123, 1391, 1402, 1412, 1463–1465, 1472, 526, 538
   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%691
   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.js98.62%100%100%98.62%220, 224, 226, 419, 430, 889
   Stats.js100%100%100%100%
   Template.js100%100%100%100%
   TemplatedPathPlugin.js99.43%100%100%99.43%308–309
   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%371
   cli.js98.63%100%100%98.63%10, 119, 549, 581, 631, 905
   index.js99.72%100%100%99.72%184
   validateSchema.js94.67%100%100%94.67%100, 87, 89, 98
   webpack.js97.10%100%100%97.10%10, 263, 285, 287
lib/asset
   AssetBytesGenerator.js100%100%100%100%
   AssetBytesParser.js100%100%100%100%
   AssetGenerator.js100%100%100%100%
   AssetModule.js100%100%100%100%
   AssetModulesPlugin.js97.95%100%100%97.95%295, 319, 322, 42, 452, 47
   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.js95.83%100%100%95.83%33
   MemoryWithGcCachePlugin.js93.15%100%100%93.15%107, 114–115, 123, 90
   PackFileCacheStrategy.js96.52%100%100%96.52%1310, 1410, 1414, 1476, 1712, 1796, 1819, 1851, 675, 694, 704–706, 708, 724–725, 730, 733, 735, 740, 745, 770, 776, 810, 816, 822, 827, 838, 847, 852–853, 855, 872, 878–879, 881
   ResolverCachePlugin.js100%100%100%100%
   getLazyHashedEtag.js100%100%1

@alexander-akait
alexander-akait merged commit d1b5b6d into main Jul 28, 2026
62 checks passed
@alexander-akait
alexander-akait deleted the fix/typescript-auto-resolve-defaults branch July 28, 2026 18:08
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.

Regression in 5.109.0: resolve.alias mapping to an absolute path that points at a package directory no longer resolves

1 participant

Sponsor
SponsoredKunjungi sekarang
Promo