Skip to content

Commit

Permalink
feat: improved multi-compiler cache location and validating it
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait committed May 8, 2024
2 parents a679033 + ca4e22c commit a705dca
Show file tree
Hide file tree
Showing 26 changed files with 264 additions and 19 deletions.
35 changes: 35 additions & 0 deletions lib/MultiCompiler.js
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
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
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
9 changes: 7 additions & 2 deletions test/ConfigTestCases.template.js
Expand Up @@ -66,7 +66,7 @@ const describeCases = config => {
describe(testName, function () {
const testDirectory = path.join(casesPath, category.name, testName);
const filterPath = path.join(testDirectory, "test.filter.js");
if (fs.existsSync(filterPath) && !require(filterPath)()) {
if (fs.existsSync(filterPath) && !require(filterPath)(config)) {
describe.skip(testName, () => {
it("filtered", () => {});
});
Expand Down 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
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
@@ -0,0 +1 @@
it("should build", () => {});
@@ -0,0 +1 @@
module.exports = config => config.cache;
@@ -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
}
];
@@ -0,0 +1 @@
it("should build", () => {});
@@ -0,0 +1 @@
module.exports = config => config.cache;
@@ -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"
}
}
];
@@ -0,0 +1 @@
it("should build", () => {});
@@ -0,0 +1 @@
module.exports = config => config.cache;
@@ -0,0 +1,4 @@
module.exports = [
/Please set unique "cache\.name" option/,
/Compiler with name "3rd compiler" doesn't use unique cache name/
];
@@ -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"
}
}
];
@@ -0,0 +1 @@
it("should build", () => {});
@@ -0,0 +1 @@
module.exports = config => config.cache;
@@ -0,0 +1 @@
module.exports = [/Please set unique "cache\.name" option/];
@@ -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"
}
}
];
@@ -0,0 +1 @@
it("should build", () => {});
@@ -0,0 +1 @@
module.exports = config => config.cache;

0 comments on commit a705dca

Please sign in to comment.