When CSS files are used as entry points (e.g., `entry: { styles: './styles.css' }`),
webpack generates an unnecessary empty .js file alongside the CSS output.
Root cause: `chunkHasJs()` returns true for any chunk with entry modules
without checking their source types, and `chunkHasRuntimeOrJs()` returns
true whenever runtime modules exist, even when there are no JavaScript
entry modules that need bootstrapping.
Fix:
- `chunkHasJs()`: Check entry module source types instead of blindly
returning true for any entry module. Only return true when at least
one entry module has JavaScript source type.
- `chunkHasRuntimeOrJs()`: When runtime modules exist but there are
entry modules in the chunk, verify that at least one entry module
has JavaScript source type before emitting JS. For standalone runtime
chunks (optimization.runtimeChunk: true), keep JS emission since the
runtime bootstrap is needed for other entry chunks.
Fixes webpack#11671
Co-authored-by: Cursor <cursoragent@cursor.com>
Human View
Summary
Fixes #11671 (5+ years old, 82 reactions).
When CSS files are used as webpack entry points, an unnecessary empty
.jsfile is generated in the output alongside the CSS. This forces users to rely on third-party plugins likewebpack-remove-empty-scripts.Before
After
// Output: dist/styles.css (only)Root Cause
Two functions in
JavascriptModulesPlugin.jscause this:chunkHasJs()(line 83) returnstruefor any chunk with entry modules, without checking their source types. CSS-only entry modules have source type"css", not"javascript".chunkHasRuntimeOrJs()(line 96) returnstruewhen runtime modules exist. But runtime modules are always added to entry chunks — for CSS-only entries, the runtime has nothing to bootstrap.Fix
chunkHasJs(): Iterate entry modules and check their source types. Only returntruewhen at least one entry module hasJAVASCRIPT_TYPE.chunkHasRuntimeOrJs(): When runtime modules exist, check for JS non-entry modules first. If only runtime + entry modules, verify entry modules have JS source type. For standalone runtime chunks (optimization.runtimeChunk: true), keep JS emission since the bootstrap code is needed.Changes
lib/javascript/JavascriptModulesPlugin.jschunkHasJsandchunkHasRuntimeOrJsto check entry module source typestest/configCases/asset-modules/only-entry/test.js.jsfilesEdge Cases Verified
.js, CSS entry drops empty.jsoptimization.runtimeChunk: true: Standalone runtime chunk keeps JS for bootstrapchunkHasJsas public API: Used by 5+ chunk loading modules — the change makes it more correct (CSS chunks truly don't have JS)Testing
only-entrytest cases pass (7 configs)vendor-only-entrypoint(runtimeChunk: true) passespure-csspassesno-extra-runtime-with-asset-modulespassesAI View (DCCE Protocol v1.0)
Metadata
AI Contribution Summary
Verification Steps Performed
Human Review Guidance
JavascriptModulesPlugin.js,lib/javascript/JavascriptModulesPlugin.js,test/configCases/asset-modules/only-entry/test.jsMade with M7 Cursor