Skip to content

test: cover CSS source map generation across all exportType values#20886

Merged
alexander-akait merged 13 commits into
mainfrom
claude/add-css-sourcemap-tests-5R8Ee
Apr 29, 2026
Merged

test: cover CSS source map generation across all exportType values#20886
alexander-akait merged 13 commits into
mainfrom
claude/add-css-sourcemap-tests-5R8Ee

Conversation

@alexander-akait
Copy link
Copy Markdown
Member

Adds two configCases test directories that compile a CSS module under
each parser.exportType (link, text, style, css-style-sheet) with
devtool: "source-map" and assert that the emitted .css.map (link) or
.js.map (text/style/css-style-sheet) is a well-formed v3 source map
containing the original source content. The companion -less directory
runs the same matrix through less-loader so the source map produced
by less-loader is verified to propagate end-to-end into the bundle's
source map.

Adds two configCases test directories that compile a CSS module under
each parser.exportType (link, text, style, css-style-sheet) with
devtool: "source-map" and assert that the emitted .css.map (link) or
.js.map (text/style/css-style-sheet) is a well-formed v3 source map
containing the original source content. The companion -less directory
runs the same matrix through less-loader so the source map produced
by less-loader is verified to propagate end-to-end into the bundle's
source map.
Folds the two source-map config cases into a single multi-config that
exercises every parser.exportType (link, text, style, css-style-sheet)
with and without less-loader (8 configurations total). Each config
aliases STYLE_UNDER_TEST to either style.css or style.less so the
shared index.js handles all combinations.

Validation now matches what Chrome DevTools requires to actually load
a map: the //# sourceMappingURL annotation in the bundle, the V3
schema (version, sources, mappings, sourcesContent length), every
segment decoded through a base64-VLQ parser with bounds checking on
source/name indices, and an additional pass through Node's built-in
node:module SourceMap consumer to confirm at least one entry resolves.
For the less-loader path the test asserts the original .less text
(@brand-color and friends) is what lands in sourcesContent, not the
post-less compiled CSS.
Copilot AI review requested due to automatic review settings April 28, 2026 15:00
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 28, 2026

🦋 Changeset detected

Latest commit: 3dba70c

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

github-actions Bot commented Apr 28, 2026

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

Install it locally:

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

Comment thread test/configCases/css/source-map-export-types/index.js Fixed
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

❌ Patch coverage is 63.15789% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.24%. Comparing base (1674988) to head (3dba70c).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
lib/css/CssGenerator.js 50.00% 7 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main   #20886       +/-   ##
===========================================
- Coverage   90.40%   80.24%   -10.17%     
===========================================
  Files         557      526       -31     
  Lines       55102    53786     -1316     
  Branches    14484    14226      -258     
===========================================
- Hits        49816    43158     -6658     
- Misses       5286    10628     +5342     
Flag Coverage Δ
integration 77.45% <63.15%> (-11.89%) ⬇️
test262 45.98% <0.00%> (-0.03%) ⬇️
unit 36.17% <0.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.

…caping or encoding'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla Bot commented Apr 28, 2026

CLA Missing ID CLA Not Signed

One or more co-authors of this pull request were not found. You must specify co-authors in commit message trailer via:

Co-authored-by: name <email>

Supported Co-authored-by: formats include:

  1. Anything <[email protected]> - it will locate your GitHub user by id part.
  2. Anything <[email protected]> - it will locate your GitHub user by login part.
  3. Anything <public-email> - it will locate your GitHub user by public-email part. Note that this email must be made public on Github.
  4. Anything <other-email> - it will locate your GitHub user by other-email part but only if that email was used before for any other CLA as a main commit author.
  5. login <any-valid-email> - it will locate your GitHub user by login part, note that login part must be at least 3 characters long.

Alternatively, if the co-author should not be included, remove the Co-authored-by: line from the commit message.

Please update your commit message(s) by doing git commit --amend and then git push [--force] and then request re-running CLA check via commenting on this pull request:

/easycla

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new configCases matrix test to validate CSS source map generation for all CSS parser.exportType values, including propagation of loader-generated source maps (via less-loader) into emitted .map files.

Changes:

  • Add a multi-compiler config that builds the same CSS module under exportType: link, text, style, and css-style-sheet (with and without less-loader).
  • Add a runtime test that reads the emitted .map files and validates v3 source map structure plus presence of original source content.
  • Add CSS/LESS fixture sources used to assert sourcesContent correctness.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test/configCases/css/source-map-export-types/webpack.config.js Defines the multi-compiler matrix across exportType values and optional less-loader preprocessing.
test/configCases/css/source-map-export-types/test.config.js Injects Node utilities into the web-targeted runtime sandbox for map file inspection.
test/configCases/css/source-map-export-types/index.js Implements source map validation (structure, mappings decode, and source content marker assertions).
test/configCases/css/source-map-export-types/style.css CSS fixture source for source-content assertions.
test/configCases/css/source-map-export-types/style.less LESS fixture source for end-to-end loader source map propagation assertions.

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

Comment thread test/configCases/css/source-map-export-types/test.config.js Outdated
Comment thread test/configCases/css/source-map-export-types/index.js
Comment thread test/configCases/css/source-map-export-types/index.js Outdated
Comment thread test/configCases/css/source-map-export-types/webpack.config.js
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 28, 2026

Merging this PR will degrade performance by 53.24%

⚡ 2 improved benchmarks
❌ 7 regressed benchmarks
✅ 135 untouched benchmarks

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

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory benchmark "side-effects-reexport", scenario '{"name":"mode-production","mode":"production"}' 4.4 MB 5.9 MB -24.42%
Memory benchmark "side-effects-reexport", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 1,000.6 KB 1,374.8 KB -27.22%
Memory benchmark "many-chunks-esm", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 899.6 KB 142.8 KB ×6.3
Memory benchmark "devtool-source-map", scenario '{"name":"mode-production","mode":"production"}' 6.1 MB 7.8 MB -21.78%
Memory benchmark "many-chunks-esm", scenario '{"name":"mode-production","mode":"production"}' 7.2 MB 9.1 MB -21.05%
Memory benchmark "many-chunks-commonjs", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 458 KB 979.3 KB -53.24%
Memory benchmark "asset-modules-resource", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 397.9 KB 683.2 KB -41.76%
Memory benchmark "many-chunks-commonjs", scenario '{"name":"mode-development","mode":"development"}' 1,306.9 KB 800.4 KB +63.27%
Memory benchmark "asset-modules-inline", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 227.6 KB 435.5 KB -47.74%

Comparing claude/add-css-sourcemap-tests-5R8Ee (3dba70c) with main (6461ec0)

Open in CodSpeed

alexander-akait and others added 10 commits April 28, 2026 20:39
When the CSS parser exportType is text, style, or css-style-sheet,
the CSS body is embedded as a JS string literal. The previous code
attached the original CSS source map to the surrounding JS source
map, but JSON.stringify collapses the CSS onto a single line and the
existing line/column information no longer matches the emitted
generated text — DevTools could not resolve mappings for CSS modules
consumed via these export types.

Append a /*# sourceMappingURL=data:application/json;charset=utf-8;base64,... */
comment to the CSS content, matching the behavior of css-loader and
style-loader. The comment travels with the CSS into whatever consumer
applies it (a <style> tag injected by the cssInjectStyle runtime, a
CSSStyleSheet.replaceSync() call, or a caller of the text default
export), so DevTools shows the original CSS / preprocessor source.

Tests: extend test/configCases/css/source-map-export-types to read
the inline data URI from the JS bundle, base64-decode it, validate
the V3 schema, decode every VLQ segment with bounds checks against
sources/names, run it through Node's built-in node:module SourceMap
consumer, and assert the original .css/.less source name and content
are present. Update test/configCases/css/export-type-source-map for
the new shape.
Coverage for the text exportType + inline data URI source map is fully
subsumed by test/configCases/css/source-map-export-types, which now
runs all four exportType values both with and without less-loader.
`findEntry(0, 0)` returns `{}` for empty or structurally invalid
maps too, so the assertion was passing trivially without catching
anything the hand-written VLQ decoder and structural checks weren't
already catching. Removing the dependency also avoids coupling the
config case to the `node:module` `SourceMap` API.
For text/style/css-style-sheet exportTypes the CSS module is emitted
as a JS string literal. After replacing SourceMapSource with RawSource
for the inline data URI fix, the bundle's JS source map no longer
included that wrapper module at all — DevTools showed only
./index.js, the runtime, and the bootstrap. Wrap the JS literal in
OriginalSource keyed by module.identifier() so the wrapper appears
as a source alongside other JS modules. Tests assert the CSS module
identifier is in jsMap.sources for every non-link config.
Previously only the inner JS string literal was wrapped, so the
bundle's JS source map sourcesContent for the CSS module entry was
the bare JSON-stringified CSS, not the actual emitted JS. Now the
entire generated module body — `__webpack_require__.r(module.exports
= { "default": "…" })` for text, the `cssInjectStyle(<id>, "…")`
runtime call for style, and the `new CSSStyleSheet()` IIFE for
css-style-sheet — is the source under the CSS module identifier,
matching what css-loader produces.

Tests assert the wrapper text (webpack runtime calls, `module.exports`
for text, `new CSSStyleSheet()` / `replaceSync` for css-style-sheet)
shows up in sourcesContent and that it does not start with a quote
character (which would indicate the old bare-literal regression).
A CSS module's raw `module.identifier()` embeds the absolute
filesystem path (e.g. `css/auto|/home/user/.../style.css|text`)
when no loader is in front of it, so passing it directly to
OriginalSource leaked absolute paths into the bundle's JS source map
`sources` for plain `.css` builds. Regular JS sources go through
`requestShortener` and end up as `webpack:///./module.js` — switch
the CSS module emit to `module.readableIdentifier(requestShortener)`
so its sources match (`webpack:///css ./style.css (exportType: text)`,
`webpack:///css ./style.less (exportType: style)`, etc.).

Add a regression assertion that strips the `webpack:///` scheme from
each source and rejects anything starting with `/` or a Windows
drive prefix.
`SourceMapDevToolPlugin` strips `sourcesContent` from the external
maps when devtool is `nosources-*-source-map`, but the inline data URI
map we embed in the CSS string for text/style/css-style-sheet
exportTypes was generated by the CSS generator on its own and was
still carrying the original CSS body. Read
`compilation.options.devtool` and drop `sourcesContent` from the
inline map when the devtool string includes `nosources`, matching the
external behavior.

Adds test/configCases/css/nosources-source-map-export-types covering
all four exportTypes: asserts the .css.map (link), the JS .map, and
the embedded data URI map all have null/empty sourcesContent and that
no original CSS rule text leaks through any of them.
@github-actions
Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging claude/add-css-sourcemap-tests-5R8Ee 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.13%100%100%98.13%371, 404
   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.49%100%100%99.49%182, 2213–2214, 2217, 2228, 2239, 2250, 278, 3596, 3611, 3635
   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%1067, 1376, 466, 478
   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%446–447, 452, 454, 518
   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.13%100%100%99.13%1291–1293, 1301, 270, 273, 278, 282, 467
   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 74e2235 into main Apr 29, 2026
56 of 60 checks passed
@alexander-akait alexander-akait deleted the claude/add-css-sourcemap-tests-5R8Ee branch April 29, 2026 18:32
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.

3 participants