Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validate compiler options in multicompiler mode #15460

Merged
merged 12 commits into from
May 8, 2024
35 changes: 35 additions & 0 deletions lib/MultiCompiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const { SyncHook, MultiHook } = require("tapable");
const ConcurrentCompilationError = require("./ConcurrentCompilationError");
const MultiStats = require("./MultiStats");
const MultiWatching = require("./MultiWatching");
const WebpackError = require("./WebpackError");
const ArrayQueue = require("./util/ArrayQueue");

/** @template T @typedef {import("tapable").AsyncSeriesHook<T>} AsyncSeriesHook<T> */
Expand Down Expand Up @@ -109,6 +110,40 @@ module.exports = class MultiCompiler {
}
});
}
this._validateCompilersOptions();
}

_validateCompilersOptions() {
if (this.compilers.length < 2) return;
/**
* @param {Compiler} compiler compiler
* @param {WebpackError} warning warning
*/
const addWarning = (compiler, warning) => {
compiler.hooks.thisCompilation.tap("MultiCompiler", compilation => {
compilation.warnings.push(warning);
});
};
const cacheNames = new Set();
for (const compiler of this.compilers) {
if (compiler.options.cache && "name" in compiler.options.cache) {
const name = compiler.options.cache.name;
if (cacheNames.has(name)) {
addWarning(
compiler,
new WebpackError(
`${
compiler.name
? `Compiler with name "${compiler.name}" doesn't use unique cache name. `
: ""
}Please set unique "cache.name" option. Name "${name}" already used.`
)
);
} else {
cacheNames.add(name);
}
}
}
}

get options() {
Expand Down
38 changes: 25 additions & 13 deletions lib/config/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ const {
getDefaultTarget
} = require("./target");

/** @typedef {import("../../declarations/WebpackOptions").CacheOptionsNormalized} CacheOptions */
/** @typedef {import("../../declarations/WebpackOptions").CacheOptions} CacheOptions */
/** @typedef {import("../../declarations/WebpackOptions").CacheOptionsNormalized} CacheOptionsNormalized */
/** @typedef {import("../../declarations/WebpackOptions").Context} Context */
/** @typedef {import("../../declarations/WebpackOptions").CssGeneratorOptions} CssGeneratorOptions */
/** @typedef {import("../../declarations/WebpackOptions").CssParserOptions} CssParserOptions */
Expand Down Expand Up @@ -60,12 +61,14 @@ const {
/** @typedef {import("../../declarations/WebpackOptions").RuleSetRules} RuleSetRules */
/** @typedef {import("../../declarations/WebpackOptions").SnapshotOptions} SnapshotOptions */
/** @typedef {import("../../declarations/WebpackOptions").Target} Target */
/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
/** @typedef {import("../../declarations/WebpackOptions").WebpackOptions} WebpackOptions */
/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptionsNormalized */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/** @typedef {import("./target").TargetProperties} TargetProperties */

const NODE_MODULES_REGEXP = /[\\/]node_modules[\\/]/i;
const DEFAULT_CACHE_NAME = "default";

/**
* Sets a constant default value when undefined
Expand Down Expand Up @@ -137,7 +140,7 @@ const A = (obj, prop, factory) => {
};

/**
* @param {WebpackOptions} options options to be modified
* @param {WebpackOptionsNormalized} options options to be modified
* @returns {void}
*/
const applyWebpackOptionsBaseDefaults = options => {
Expand All @@ -146,10 +149,11 @@ const applyWebpackOptionsBaseDefaults = options => {
};

/**
* @param {WebpackOptions} options options to be modified
* @param {WebpackOptionsNormalized} options options to be modified
* @param {number} [compilerIndex] index of compiler
* @returns {void}
*/
const applyWebpackOptionsDefaults = options => {
const applyWebpackOptionsDefaults = (options, compilerIndex) => {
F(options, "context", () => process.cwd());
F(options, "target", () => {
return getDefaultTarget(/** @type {string} */ (options.context));
Expand Down Expand Up @@ -201,10 +205,11 @@ const applyWebpackOptionsDefaults = options => {
development ? { type: /** @type {"memory"} */ ("memory") } : false
);
applyCacheDefaults(options.cache, {
name: name || "default",
name: name || DEFAULT_CACHE_NAME,
mode: mode || "production",
development,
cacheUnaffected: options.experiments.cacheUnaffected
cacheUnaffected: options.experiments.cacheUnaffected,
compilerIndex
});
const cache = !!options.cache;

Expand Down Expand Up @@ -251,7 +256,9 @@ const applyWebpackOptionsDefaults = options => {
});

applyLoaderDefaults(
/** @type {NonNullable<WebpackOptions["loader"]>} */ (options.loader),
/** @type {NonNullable<WebpackOptionsNormalized["loader"]>} */ (
options.loader
),
{ targetProperties, environment: options.output.environment }
);

Expand All @@ -268,7 +275,7 @@ const applyWebpackOptionsDefaults = options => {

applyNodeDefaults(options.node, {
futureDefaults:
/** @type {NonNullable<WebpackOptions["experiments"]["futureDefaults"]>} */
/** @type {NonNullable<WebpackOptionsNormalized["experiments"]["futureDefaults"]>} */
(options.experiments.futureDefaults),
outputModule: options.output.module,
targetProperties
Expand All @@ -282,7 +289,7 @@ const applyWebpackOptionsDefaults = options => {
: false
);
applyPerformanceDefaults(
/** @type {NonNullable<WebpackOptions["performance"]>} */
/** @type {NonNullable<WebpackOptionsNormalized["performance"]>} */
(options.performance),
{
production
Expand Down Expand Up @@ -354,22 +361,27 @@ const applyExperimentsDefaults = (
};

/**
* @param {CacheOptions} cache options
* @param {CacheOptionsNormalized} cache options
* @param {Object} options options
* @param {string} options.name name
* @param {Mode} options.mode mode
* @param {boolean} options.development is development mode
* @param {number} [options.compilerIndex] index of compiler
* @param {Experiments["cacheUnaffected"]} options.cacheUnaffected the cacheUnaffected experiment is enabled
* @returns {void}
*/
const applyCacheDefaults = (
cache,
{ name, mode, development, cacheUnaffected }
{ name, mode, development, cacheUnaffected, compilerIndex }
) => {
if (cache === false) return;
switch (cache.type) {
case "filesystem":
F(cache, "name", () => name + "-" + mode);
F(cache, "name", () =>
compilerIndex !== undefined
? `${name + "-" + mode}__compiler${compilerIndex + 1}__`
: name + "-" + mode
);
D(cache, "version", "");
F(cache, "cacheDirectory", () => {
const cwd = process.cwd();
Expand Down
9 changes: 6 additions & 3 deletions lib/webpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ const getValidateSchema = memoize(() => require("./validateSchema"));
* @returns {MultiCompiler} a multi-compiler
*/
const createMultiCompiler = (childOptions, options) => {
const compilers = childOptions.map(options => createCompiler(options));
const compilers = childOptions.map((options, index) =>
createCompiler(options, index)
);
const compiler = new MultiCompiler(compilers, options);
for (const childCompiler of compilers) {
if (childCompiler.options.dependencies) {
Expand All @@ -57,9 +59,10 @@ const createMultiCompiler = (childOptions, options) => {

/**
* @param {WebpackOptions} rawOptions options object
* @param {number} [compilerIndex] index of compiler
* @returns {Compiler} a compiler
*/
const createCompiler = rawOptions => {
const createCompiler = (rawOptions, compilerIndex) => {
const options = getNormalizedWebpackOptions(rawOptions);
applyWebpackOptionsBaseDefaults(options);
const compiler = new Compiler(
Expand All @@ -79,7 +82,7 @@ const createCompiler = rawOptions => {
}
}
}
applyWebpackOptionsDefaults(options);
applyWebpackOptionsDefaults(options, compilerIndex);
compiler.hooks.environment.call();
compiler.hooks.afterEnvironment.call();
new WebpackOptionsApply().process(options, compiler);
Expand Down
7 changes: 6 additions & 1 deletion test/ConfigTestCases.template.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,14 @@ const describeCases = config => {
if (config.cache) {
options.cache = {
cacheDirectory,
name: `config-${idx}`,
name:
options.cache && options.cache !== true
? options.cache.name
: `config-${idx}`,
...config.cache
};
}
if (config.cache) {
options.infrastructureLogging = {
debug: true,
console: createLogger(infraStructureLog)
Expand Down
11 changes: 11 additions & 0 deletions test/StatsTestCases.basictest.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ describe("StatsTestCases", () => {
if (!options.optimization) options.optimization = {};
if (options.optimization.minimize === undefined)
options.optimization.minimize = false;
if (
options.cache &&
options.cache !== true &&
options.cache.type === "filesystem"
) {
options.cache.cacheDirectory = path.resolve(
outputBase,
".cache",
testName
);
}
});
const c = webpack(options);
const compilers = c.compilers ? c.compilers : [c];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
it("should build", () => {});
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use strict";

// default settings. should just work

/** @type {import("../../../../").Configuration} */
module.exports = [
{
mode: "production",
entry: "./index",
cache: {
type: "filesystem",
name: "name2"
}
},
{
mode: "production",
entry: "./index",
cache: {
type: "filesystem",
name: "name1"
}
},
{
mode: "production",
entry: "./index",
cache: true
},
{
mode: "production",
entry: "./index",
cache: true
}
];
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
it("should build", () => {});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use strict";

// no cache names

/** @type {import("../../../../").Configuration} */
module.exports = [
{
mode: "production",
entry: "./index",
cache: {
type: "filesystem"
}
},
{
mode: "production",
entry: "./index",
cache: {
type: "filesystem"
}
},
{
name: "3rd compiler",
mode: "production",
entry: "./index",
cache: {
type: "filesystem"
}
}
];
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
it("should build", () => {});
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = [
/Please set unique "cache\.name" option/,
/Compiler with name "3rd compiler" doesn't use unique cache name/
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use strict";

// with explicit cache names

/** @type {import("../../../../").Configuration} */
module.exports = [
{
mode: "production",
entry: "./index",
cache: {
name: "filesystem",
type: "filesystem"
}
},
{
mode: "production",
entry: "./index",
cache: {
name: "filesystem",
type: "filesystem"
}
},
{
name: "3rd compiler",
mode: "production",
entry: "./index",
cache: {
name: "filesystem",
type: "filesystem"
}
}
];
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
it("should build", () => {});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = [/Please set unique "cache\.name" option/];
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use strict";

// with explicit cache names

/** @type {import("../../../../").Configuration} */
module.exports = [
{
mode: "production",
entry: "./index",
cache: {
name: "default",
type: "filesystem"
}
},
{
mode: "production",
entry: "./index",
cache: {
name: "default",
type: "filesystem"
}
}
];
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
it("should build", () => {});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use strict";

// no cache names

/** @type {import("../../../../").Configuration} */
module.exports = [
{
mode: "production",
entry: "./index",
cache: {
type: "filesystem",
name: "default"
}
},
{
mode: "production",
entry: "./index",
cache: {
type: "filesystem"
}
}
];