Skip to content

feat: add output.workerChunkFilename to set the worker chunk filename template#21128

Merged
alexander-akait merged 12 commits into
mainfrom
feat/worker-chunk-filename
Jun 9, 2026
Merged

feat: add output.workerChunkFilename to set the worker chunk filename template#21128
alexander-akait merged 12 commits into
mainfrom
feat/worker-chunk-filename

Conversation

@alexander-akait

@alexander-akait alexander-akait commented Jun 8, 2026

Copy link
Copy Markdown
Member

Summary

Adds output.workerChunkFilename so the filename template of worker chunks can be set independently of output.chunkFilename/output.filename. WorkerPlugin applies it to the worker entrypoint's filename, so it scopes only to worker chunks; per-worker webpackEntryOptions.filename still wins. Defaults to output.chunkFilename.

Closes #17002.
Closes #19280

What kind of change does this PR introduce?

feat

Did you add tests for your changes?

Yes — test/configCases/worker/worker-chunk-filename (string/function forms across filename/chunkFilename combinations) and test/configCases/worker/worker-chunk-filename-multiple-entries (confirms it targets only the worker, not other entries); updated Defaults.unittest.js, Validation.test.js, Cli.basictest.js snapshots.

Does this PR introduce a breaking change?

No. Because it defaults to output.chunkFilename, worker entry filenames now follow chunkFilename (previously filename) when the two differ; set workerChunkFilename explicitly to opt out.

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

Document output.workerChunkFilename: filename template for non-initial worker files, same type as output.chunkFilename, default output.chunkFilename.

Use of AI

AI (Claude Code) was used to port the change onto current main, regenerate the auto-generated types/schemas, and write the tests; all changes were reviewed by a human.


Generated by Claude Code

@changeset-bot

changeset-bot Bot commented Jun 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a629385

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

Copy link
Copy Markdown
Contributor

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

Install it locally:

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

@codecov

codecov Bot commented Jun 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.34%. Comparing base (d39efba) to head (a629385).
⚠️ Report is 14 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #21128      +/-   ##
==========================================
+ Coverage   92.33%   92.34%   +0.01%     
==========================================
  Files         581      581              
  Lines       62942    63288     +346     
  Branches    17420    17507      +87     
==========================================
+ Hits        58117    58443     +326     
- Misses       4825     4845      +20     
Flag Coverage Δ
css-parsing 28.65% <25.00%> (-0.04%) ⬇️
html5lib 31.03% <25.00%> (+0.26%) ⬆️
integration 88.51% <100.00%> (-0.05%) ⬇️
test262 45.31% <56.25%> (+0.04%) ⬆️
unit 41.09% <25.00%> (+0.14%) ⬆️

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.

… caching

A function-valued worker filename stored in the AsyncDependenciesBlock broke
persistent caching of the worker-creating module. Apply it to the worker
entrypoint chunk from outputOptions in afterChunks instead.

https://claude.ai/code/session_01NBzMSamAkDoccgnWuENzJj
@codspeed-hq

codspeed-hq Bot commented Jun 8, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 33.71%

⚠️ 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
✅ 142 untouched benchmarks

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory benchmark "css-modules", scenario '{"name":"mode-production","mode":"production"}' 9.1 MB 6.7 MB +36.74%
Memory benchmark "asset-modules-bytes", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 321.8 KB 246.1 KB +30.74%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing feat/worker-chunk-filename (a629385) with main (41985a4)

Open in CodSpeed

…d of a hook

Worker entry chunks are non-initial entrypoints, so getChunkFilenameTemplate
(and the runtime chunk-filename closure) can return output.workerChunkFilename
directly via chunk.getEntryOptions(). Removes the WorkerPlugin afterChunks hook
and the per-block filename, avoiding chunk mutation and the cache issue entirely.

https://claude.ai/code/session_01NBzMSamAkDoccgnWuENzJj
…er chunk loading)

The workers loaded a dynamically-imported sub-chunk, whose in-worker chunk
loading fails on node 12.17 (works on 14+). Use a static import so the worker
is self-contained; it still covers workerChunkFilename on the worker entry.

https://claude.ai/code/session_01NBzMSamAkDoccgnWuENzJj
…he entry

Name every chunk reachable solely from worker entrypoints (the worker entry
chunk and its internal async chunks) with output.workerChunkFilename. Chunks
also reachable from an initial entrypoint (shared) stay on output.chunkFilename.
Computed in afterOptimizeChunks via getAllReferencedChunks; the pass is skipped
unless a distinct workerChunkFilename is set and workers exist.

https://claude.ai/code/session_01NBzMSamAkDoccgnWuENzJj
Apply output.workerChunkFilename only to the worker script itself (a
non-initial entry chunk). Chunks a worker loads internally via import() are
not entry chunks and keep using output.chunkFilename. Resolved via
chunk.getEntryOptions() in getChunkFilenameTemplate and the runtime
chunk-filename helper; no seal-time pass needed.

https://claude.ai/code/session_01NBzMSamAkDoccgnWuENzJj
…m entry options

Set `worker: true` on the worker entry's EntryOptions in WorkerPlugin and
key the workerChunkFilename lookup off that flag, so a non-worker async
entrypoint is no longer treated as a worker.

https://claude.ai/code/session_01NBzMSamAkDoccgnWuENzJj
…rkers

`webpackEntryOptions` only applies to workers; emit a warning when it is
used in a dynamic `import()`. Add a worker test that loads multiple
chunks to confirm they all keep `chunkFilename` while only the worker
entry uses `workerChunkFilename`.

https://claude.ai/code/session_01NBzMSamAkDoccgnWuENzJj
Warn only when the internal `worker` entry option is set via a dynamic
`import()`, instead of warning on any `webpackEntryOptions`.

https://claude.ai/code/session_01NBzMSamAkDoccgnWuENzJj
Expose `worker` as a documented entry-description option so an entry can
be built as a worker (and reused from another entry) directly in
`webpack.config.js`, driving `output.workerChunkFilename`. The marker now
lives on the public entry schema instead of an internal-only typedef.

https://claude.ai/code/session_01NBzMSamAkDoccgnWuENzJj
…untimePlugin

Drop the duplicated worker/initial/chunk filename selection from the
getChunkScriptFilename runtime closure and delegate to the existing
static, mirroring how the CSS path uses CssModulesPlugin.

https://claude.ai/code/session_01NBzMSamAkDoccgnWuENzJj
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging feat/worker-chunk-filename into main will be
99.33%
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.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-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%
   CleanPlugin.js99.15%100%100%99.15%206, 226
   CodeGenerationResults.js100%100%100%100%
   CompatibilityPlugin.js100%100%100%100%
   Compilation.js98.49%100%100%98.49%1577, 1873, 1880, 1888, 1910, 2806, 3249, 3924, 3954, 4007–4008, 4012, 4017, 4033–4034, 4048–4049, 4054–4055, 4532, 4558, 512, 517, 5366, 5398, 5415, 5431, 5447, 5462, 5487–5488, 5490, 5818, 5823, 5829, 5832, 5844, 5846, 5850, 5866, 5881, 5913, 5967, 5991, 6105, 731–732
   Compiler.js99.56%100%100%99.56%1135–1136, 1144
   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.40%100%100%97.40%258, 395, 418, 420, 424, 433–434
   ContextReplacementPlugin.js100%100%100%100%
   DefinePlugin.js99%100%100%99%170–171, 187, 206, 280
   DependenciesBlock.js100%100%100%100%
   Dependency.js98.15%100%100%98.15%379, 425
   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.97%100%100%98.97%425–429, 577
   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, 3693, 3708, 3732
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.85%100%100%98.85%434, 436, 440
   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%1311, 1316, 1376, 1390, 1452, 1461
   ModuleFactory.js100%100%100%100%
   ModuleFilenameHelpers.js98.85%100%100%98.85%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.69%100%100%99.69%659
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js97.90%100%100%97.90%1219, 1222, 1239, 1256, 1503, 1537, 1553, 1640, 1994, 2292, 2297–2307, 417, 421, 575
   NormalModuleFactory.js99.47%100%100%99.47%1083, 1392, 486, 498
   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.js98.62%100%100%98.62%220, 224, 226, 419, 430, 891
   Stats.js100%100%100%100%
   Template.js100%100%100%100%
   TemplatedPathPlugin.js99.13%100%100%99.13%176–177
   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%326
   cli.js98.62%100%100%98.62%10, 119, 545, 577, 627, 897
   index.js99.72%100%100%99.72%165
   validateSchema.js94.67%100%100%94.67%100, 87, 89, 98
   webpack.js96.33%100%100%96.33%10, 198, 220, 222
lib/asset
   AssetBytesGenerator.js100%100%100%100%
   AssetBytesParser.js100%100%100%100%
   AssetGenerator.js100%100%100%100%
   AssetModulesPlugin.js97.32%100%100%97.32%283, 307, 310, 36, 362, 41
   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.30%100%100%99.30%1429–1431, 1439, 274, 277, 282, 286
   normalization.js99.01%100%100%99.01%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%

@alexander-akait alexander-akait merged commit 87394de into main Jun 9, 2026
65 of 66 checks passed
@alexander-akait alexander-akait deleted the feat/worker-chunk-filename branch June 9, 2026 14:22
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.

Introduce a new option for workers chunks' filenames

1 participant