Skip to content

fix(css): add processContent hook and async code generation support#20736

Draft
xiaoxiaojx wants to merge 2 commits into
mainfrom
feat/process-content-hook
Draft

fix(css): add processContent hook and async code generation support#20736
xiaoxiaojx wants to merge 2 commits into
mainfrom
feat/process-content-hook

Conversation

@xiaoxiaojx
Copy link
Copy Markdown
Member

@xiaoxiaojx xiaoxiaojx commented Mar 29, 2026

Summary
webpack/css-minimizer-webpack-plugin#311 Add compilation.hooks.processContent AsyncSeriesWaterfallHook for plugins to transform module content (e.g., CSS minimization) during code generation. The hook uses a pure functional waterfall design — plugins receive [content, sourceMap] and return a new tuple, avoiding in-place mutation. Designed as async to support minimizers that leverage worker threads for parallel processing.

What kind of change does this PR introduce?
fix

Did you add tests for your changes?
Yes

Does this PR introduce a breaking change?
No

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

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 29, 2026

🦋 Changeset detected

Latest commit: ba3f97c

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
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 29, 2026

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

Install it locally:

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

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 29, 2026

Codecov Report

❌ Patch coverage is 93.75000% with 29 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.42%. Comparing base (925ba2d) to head (ba3f97c).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
lib/optimize/ConcatenatedModule.js 91.41% 28 Missing ⚠️
lib/Template.js 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main   #20736   +/-   ##
=======================================
  Coverage   91.42%   91.42%           
=======================================
  Files         559      559           
  Lines       55091    55161   +70     
  Branches    14528    14546   +18     
=======================================
+ Hits        50368    50432   +64     
- Misses       4723     4729    +6     
Flag Coverage Δ
integration 90.41% <93.75%> (+<0.01%) ⬆️
test262 41.98% <4.74%> (+0.01%) ⬆️
unit 36.18% <4.74%> (-0.02%) ⬇️

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.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Mar 29, 2026

Merging this PR will degrade performance by 67.32%

⚠️ 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

⚡ 9 improved benchmarks
❌ 11 regressed benchmarks
✅ 124 untouched benchmarks

⚠️ 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-development-rebuild","mode":"development","watch":true}' 1,256 KB 415.1 KB ×3
Memory benchmark "asset-modules-source", scenario '{"name":"mode-development","mode":"development"}' 682.4 KB 919.9 KB -25.81%
Memory benchmark "many-modules-commonjs", scenario '{"name":"mode-development","mode":"development"}' 988.9 KB 1,303.1 KB -24.11%
Memory benchmark "react", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 863.8 KB 651.5 KB +32.59%
Memory benchmark "json-modules", scenario '{"name":"mode-development","mode":"development"}' 1,551.5 KB 533.1 KB ×2.9
Memory benchmark "devtool-eval-source-map", scenario '{"name":"mode-development","mode":"development"}' 2,309.8 KB 973.9 KB ×2.4
Memory benchmark "asset-modules-resource", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 1,052 KB 731.7 KB +43.78%
Memory benchmark "devtool-eval", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 410.8 KB 1,256.9 KB -67.32%
Memory benchmark "many-chunks-commonjs", scenario '{"name":"mode-production","mode":"production"}' 8.7 MB 7.1 MB +21.36%
Memory benchmark "many-chunks-esm", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 902.2 KB 707.9 KB +27.44%
Memory benchmark "lodash", scenario '{"name":"mode-development","mode":"development"}' 4.1 MB 5.3 MB -22.68%
Memory benchmark "asset-modules-source", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 826.1 KB 266 KB ×3.1
Memory benchmark "cache-filesystem", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 762.8 KB 1,026.1 KB -25.67%
Memory benchmark "many-modules-esm", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 310.9 KB 801.4 KB -61.21%
Memory benchmark "concatenate-modules", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 781.7 KB 556.2 KB +40.54%
Memory benchmark "devtool-source-map", scenario '{"name":"mode-development","mode":"development"}' 957.6 KB 1,404.2 KB -31.8%
Memory benchmark "json-modules", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 628.6 KB 997.8 KB -37.01%
Memory benchmark "devtool-source-map", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 409.9 KB 735.2 KB -44.25%
Memory benchmark "devtool-eval", scenario '{"name":"mode-development","mode":"development"}' 1.1 MB 2.2 MB -50.11%
Memory benchmark "many-chunks-esm", scenario '{"name":"mode-development","mode":"development"}' 1.1 MB 1.4 MB -21.86%

Comparing feat/process-content-hook (ba3f97c) with main (cfc5e36)

Open in CodSpeed

Copy link
Copy Markdown
Member

@alexander-akait alexander-akait left a comment

Choose a reason for hiding this comment

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

Looks good, I want to make a new release 31 or 1, let's merge it after this

@github-actions
Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging feat/process-content-hook into main will be
98.95%
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%
lib
   APIPlugin.js100%100%100%100%
   AbstractMethodError.js100%100%100%100%
   AsyncDependenciesBlock.js100%100%100%100%
   AsyncDependencyToInitialChunkError.js100%100%100%100%
   AutomaticPrefetchPlugin.js100%100%100%100%
   BannerPlugin.js100%100%100%100%
   Cache.js98.21%100%100%98.21%87
   CacheFacade.js100%100%100%100%
   CaseSensitiveModulesWarning.js100%100%100%100%
   Chunk.js99.72%100%100%99.72%37
   ChunkGraph.js100%100%100%100%
   ChunkGroup.js100%100%100%100%
   ChunkRenderError.js100%100%100%100%
   ChunkTemplate.js100%100%100%100%
   CleanPlugin.js98.72%100%100%98.72%196, 216, 371
   CodeGenerationError.js100%100%100%100%
   CodeGenerationResults.js100%100%100%100%
   CommentCompilationWarning.js100%100%100%100%
   CompatibilityPlugin.js100%100%100%100%
   Compilation.js98.58%100%100%98.58%1517, 1806, 1813, 1821, 1843, 2719, 3137, 3791, 3887–3888, 3892, 3897, 3913–3914, 3928–3929, 3934–3935, 4397, 4423, 473, 478, 5118, 5198, 5213, 5238–5239, 5241, 5557, 5562, 5568, 5571, 5583, 5585, 5589, 5605, 5620, 5651, 5705, 5729, 5839, 684–685
   Compiler.js99.56%100%100%99.56%1091–1092, 1100
   ConcatenationScope.js98.59%100%100%98.59%166
   ConcurrentCompilationError.js100%100%100%100%
   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%253, 385, 410, 435, 439, 450
   ContextReplacementPlugin.js100%100%100%100%
   CssModule.js81.32%100%100%81.32%152, 157–172
   DefinePlugin.js98.92%100%100%98.92%153–154, 170, 189, 263
   DelegatedModule.js95.24%100%100%95.24%240–244
   DelegatedModuleFactoryPlugin.js98.15%100%100%98.15%103
   DelegatedPlugin.js100%100%100%100%
   DependenciesBlock.js100%100%100%100%
   Dependency.js98.13%100%100%98.13%351, 381
   DependencyTemplate.js100%100%100%100%
   DependencyTemplates.js100%100%100%100%
   DllEntryPlugin.js100%100%100%100%
   DllModule.js100%100%100%100%
   DllModuleFactory.js100%100%100%100%
   DllPlugin.js100%100%100%100%
   DllReferencePlugin.js100%100%100%100%
   DotenvPlugin.js97.88%100%100%97.88%235, 375, 388–389
   DynamicEntryPlugin.js100%100%100%100%
   EntryOptionPlugin.js100%100%100%100%
   EntryPlugin.js100%100%100%100%
   Entrypoint.js100%100%100%100%
   EnvironmentNotSupportAsyncWarning.js100%100%100%100%
   EnvironmentPlugin.js97.14%100%100%97.14%48
   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%385–389, 526
   ExternalModuleFactoryPlugin.js100%100%100%100%
   ExternalsPlugin.js100%100%100%100%
   FalseIIFEUmdWarning.js100%100%100%100%
   FileSystemInfo.js99.49%100%100%99.49%168, 2142–2143, 2146, 2157, 2168, 2179, 261, 3497, 3512, 3536
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.74%100%100%98.74%396, 398, 402
   FlagDependencyUsagePlugin.js100%100%100%100%
   FlagEntryExportAsUsedPlugin.js100%100%100%100%
   Generator.js100%100%100%100%
   GraphHelpers.js100%100%100%100%
   HarmonyLinkingError.js100%100%100%100%
   HookWebpackError.js100%100%100%100%
   HotModuleReplacementPlugin.js100%100%100%100%
   HotUpdateChunk.js100%100%100%100%
   IgnoreErrorModuleFactory.js100%100%100%100%
   IgnorePlugin.js100%100%100%100%
   IgnoreWarningsPlugin.js100%100%100%100%
   InitFragment.js100%100%100%100%
   InvalidDependenciesModuleWarning.js100%100%100%100%
   JavascriptMetaInfoPlugin.js100%100%100%100%
   LibManifestPlugin.js97.14%100%100%97.14%114, 117
   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.51%100%100%98.51%1185, 1190, 1248, 1261, 1318, 1326
   ModuleBuildError.js100%100%100%100%
   ModuleDependencyError.js100%100%100%100%
   ModuleDependencyWarning.js100%100%100%100%
   ModuleError.js100%100%100%100%
   ModuleFactory.js100%100%100%100%
   ModuleFilenameHelpers.js98.85%100%100%98.85%105, 107
   ModuleGraph.js99.73%100%100%99.73%942
   ModuleGraphConnection.js100%100%100%100%
   ModuleHashingError.js100%100%100%100%
   ModuleInfoHeaderPlugin.js100%100%100%100%
   ModuleNotFoundError.js100%100%100%100%
   ModuleParseError.js100%100%100%100%
   ModuleProfile.js100%100%100%100%
   ModuleRestoreError.js100%100%100%100%
   ModuleSourceTypeConstants.js100%100%100%100%
   ModuleStoreError.js100%100%100%100%
   ModuleTemplate.js100%100%100%100%
   ModuleTypeConstants.js100%100%100%100%
   ModuleWarning.js100%100%100%100%
   MultiCompiler.js99.69%100%100%99.69%619
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NoModeWarning.js100%100%100%100%
   NodeStuffInWebError.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js97.81%100%100%97.81%1032, 1048, 1135, 1785, 1790–1800, 214, 722, 740, 757, 998
   NormalModuleFactory.js99.46%100%100%99.46%1032, 1337, 447, 459
   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.75%100%100%98.75%431–432, 437, 439, 503
   ProvidePlugin.js100%100%100%100%
   RawModule.js100%100%100%100%
   RecordIdsPlugin.js100%100%100%100%
   RequestShortener.js100%100%100%100%
   RequireJsStuffPlugin.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%
   SizeFormatHelpers.js100%100%100%100%
   SourceMapDevToolModuleOptionsPlugin.js100%100%100%100%
   SourceMapDevToolPlugin.js99.16%100%100%99.16%265–266, 608
   Stats.js100%100%100%100%
   Template.js100%100%100%100%
   TemplatedPathPlugin.js98.85%100%100%98.85%128–129
   UnhandledSchemeError.js100%100%100%100%
   UnsupportedFeatureWarning.js100%100%100%100%
   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.js96.97%100%100%96.97%43
   WebpackIsIncludedPlugin.js100%100%100%100%
   WebpackOptionsApply.js100%100%100%100%
   WebpackOptionsDefaulter.js100%100%100%100%
   buildChunkGraph.js99.87%100%100%99.87%317
   cli.js98.71%100%100%98.71%109, 453, 485, 527, 787
   formatLocation.js100%100%100%100%
   index.js100%100%100%100%
   validateSchema.js94.67%100%100%94.67%86, 88, 97, 99
   webpack.js97.22%100%100%97.22%186, 208, 210
lib/asset
   AssetBytesGenerator.js100%100%100%100%
   AssetBytesParser.js100%100%100%100%
   AssetGenerator.js100%100%100%100%
   AssetModulesPlugin.js97.77%100%100%97.77%282, 306, 309, 361, 39
   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%70, 82, 90
   MemoryCachePlugin.js95.83%100%100%95.83%33
   MemoryWithGcCachePlugin.js93.15%100%100%93.15%104, 111–112, 120, 87
   PackFileCacheStrategy.js96.40%100%100%96.40%1225, 1325,

Comment thread lib/Compilation.js
afterCodeGeneration: new SyncHook([]),

/** @type {AsyncSeriesWaterfallHook<[ProcessContentSource, string]>} */
processContent: new AsyncSeriesWaterfallHook(["source", "name"]),
Copy link
Copy Markdown
Member

@alexander-akait alexander-akait Mar 31, 2026

Choose a reason for hiding this comment

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

I looked deeply on this PR and I think we need to make improvements:

  1. Let's split this PRs into multiple - processContent (maybe even codeGeneration name hook to align naming everywhere) hook and then make code generation async (we will merge them in one release, so we will not have problems here), for better history and review
  2. I think we should run processContent on compilation level (i.e. inside Compilation.js), not only for CSS modules, why? processContent can be useful not only for CSS modules, also we can use it for HTML modules (future support) in JS, also it can be useful for asset modules too - compress images before insert them as base64/bytes and more, so for me we should have this hook for any types code generations

@xiaoxiaojx xiaoxiaojx marked this pull request as draft March 31, 2026 17:27
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