Bug report
optimization.minimize: true crashes in 5.110.0 when a plugin sets it on already-normalized options
What is the current behavior?
A build throws during createCompiler:
TypeError: Cannot create property 'javascript' on boolean 'true'
at F (webpack/lib/config/defaults.js:260:13)
at applyOptimizationDefaults (webpack/lib/config/defaults.js:2471:3)
at applyWebpackOptionsDefaults (webpack/lib/config/defaults.js:572:2)
at createCompiler (webpack/lib/webpack.js:174:33)
The new per-asset-type canonicalization added in 5.110.0 (#21663, #21537) guards on truthiness rather than type:
F(optimization, "minimize", () => (production ? {} : false));
const { minimize } = optimization;
if (minimize) {
F(minimize, "javascript", () => ({ compress: { passes: 2 } }));
F(minimize, "css", () => ({}));
F(minimize, "html", () => ({}));
}
F assigns when the property is undefined, so with minimize === true this evaluates true.javascript = {...}, which throws in strict mode.
getNormalizedOptimizationMinimize already maps true to {}, so a plain config object is fine. The gap is that createCompiler normalizes first and applies plugins afterwards:
const createCompiler = (rawOptions, compilerIndex) => {
let options = getNormalizedWebpackOptions(rawOptions); // true -> {}
applyWebpackOptionsBaseDefaults(options);
...
for (const plugin of options.plugins) plugin.apply(compiler); // plugin writes minimize: true
const resolvedDefaultOptions = applyWebpackOptionsDefaults(options, compilerIndex); // throws
Any plugin that assigns compiler.options.optimization.minimize from a boolean in apply() writes a value normalization no longer gets to see. That pattern was harmless in every 5.x before this one: 5.109.2 only ever reads the option for truthiness (WebpackOptionsApply.js:819) and fills it with D(optimization, "minimize", production).
If the current behavior is a bug, please provide the steps to reproduce.
// webpack.config.js
class SetMinimize {
apply(compiler) {
compiler.options.optimization.minimize = true;
}
}
module.exports = {
mode: 'production',
plugins: [new SetMinimize()],
};
npx webpack throws on 5.110.0 and succeeds on 5.109.2. Verified against both: on 5.109.2 the build emits main.js 18 bytes [minimized], so the boolean was doing real work rather than being quietly ignored.
What is the expected behavior?
The build succeeds, with true treated as the documented shorthand for "minimize with defaults", the same way getNormalizedOptimizationMinimize treats it.
Worth noting that schemas/WebpackOptions.json in 5.110.0 still declares the boolean as valid:
"minimize": {
"anyOf": [{ "type": "boolean" }, { "$ref": "#/definitions/OptimizationMinimizeOptions" }]
}
so a config carrying true validates and then crashes.
A one-line coercion in applyOptimizationDefaults restores the old behavior and keeps the new object form intact:
F(optimization, "minimize", () => (production ? {} : false));
+ // A plugin can assign the `true` shorthand to already-normalized options,
+ // which `getNormalizedOptimizationMinimize` never sees.
+ if (optimization.minimize === true) optimization.minimize = {};
const { minimize } = optimization;
if (minimize) {
I applied that against 5.110.0 locally and the repro above compiles, emitting the same main.js 18 bytes [minimized] as 5.109.2. Happy to open a PR with it plus a regression test if the approach looks right.
Other relevant information
- webpack version: 5.110.0 (5.109.2 unaffected)
- Node.js version: 20
- Operating System: Linux
- Additional tools: webpack-cli 7.2.2
Found via @nx/webpack, whose plugin sets the option in apply(). Given that compiler.options is a documented mutation point for plugins and the boolean is still schema-valid, other plugins are likely to be affected too.
Bug report
optimization.minimize: truecrashes in 5.110.0 when a plugin sets it on already-normalized optionsWhat is the current behavior?
A build throws during
createCompiler:The new per-asset-type canonicalization added in 5.110.0 (#21663, #21537) guards on truthiness rather than type:
Fassigns when the property isundefined, so withminimize === truethis evaluatestrue.javascript = {...}, which throws in strict mode.getNormalizedOptimizationMinimizealready mapstrueto{}, so a plain config object is fine. The gap is thatcreateCompilernormalizes first and applies plugins afterwards:Any plugin that assigns
compiler.options.optimization.minimizefrom a boolean inapply()writes a value normalization no longer gets to see. That pattern was harmless in every 5.x before this one: 5.109.2 only ever reads the option for truthiness (WebpackOptionsApply.js:819) and fills it withD(optimization, "minimize", production).If the current behavior is a bug, please provide the steps to reproduce.
npx webpackthrows on 5.110.0 and succeeds on 5.109.2. Verified against both: on 5.109.2 the build emitsmain.js 18 bytes [minimized], so the boolean was doing real work rather than being quietly ignored.What is the expected behavior?
The build succeeds, with
truetreated as the documented shorthand for "minimize with defaults", the same waygetNormalizedOptimizationMinimizetreats it.Worth noting that
schemas/WebpackOptions.jsonin 5.110.0 still declares the boolean as valid:so a config carrying
truevalidates and then crashes.A one-line coercion in
applyOptimizationDefaultsrestores the old behavior and keeps the new object form intact:F(optimization, "minimize", () => (production ? {} : false)); + // A plugin can assign the `true` shorthand to already-normalized options, + // which `getNormalizedOptimizationMinimize` never sees. + if (optimization.minimize === true) optimization.minimize = {}; const { minimize } = optimization; if (minimize) {I applied that against 5.110.0 locally and the repro above compiles, emitting the same
main.js 18 bytes [minimized]as 5.109.2. Happy to open a PR with it plus a regression test if the approach looks right.Other relevant information
Found via
@nx/webpack, whose plugin sets the option inapply(). Given thatcompiler.optionsis a documented mutation point for plugins and the boolean is still schema-valid, other plugins are likely to be affected too.