diff --git a/packages/configtest/src/index.ts b/packages/configtest/src/index.ts index 53fa9c1ebc8..7fa6297bd2e 100644 --- a/packages/configtest/src/index.ts +++ b/packages/configtest/src/index.ts @@ -21,13 +21,19 @@ class ConfigTestCommand { if (Array.isArray(config.options)) { config.options.forEach((options) => { - if (config.path.get(options)) { - configPaths.add(config.path.get(options) as string); + const loadedConfigPaths = config.path.get(options); + + if (loadedConfigPaths) { + loadedConfigPaths.forEach((path) => configPaths.add(path)); } }); } else { if (config.path.get(config.options)) { - configPaths.add(config.path.get(config.options) as string); + const loadedConfigPaths = config.path.get(config.options); + + if (loadedConfigPaths) { + loadedConfigPaths.forEach((path) => configPaths.add(path)); + } } } diff --git a/packages/webpack-cli/src/plugins/cli-plugin.ts b/packages/webpack-cli/src/plugins/cli-plugin.ts index f53cc835187..a9d819c3c62 100644 --- a/packages/webpack-cli/src/plugins/cli-plugin.ts +++ b/packages/webpack-cli/src/plugins/cli-plugin.ts @@ -53,7 +53,11 @@ export class CLIPlugin { logCompilation(`Compiler${name ? ` ${name}` : ""} starting... `); if (configPath) { - this.logger.log(`Compiler${name ? ` ${name}` : ""} is using config: '${configPath}'`); + this.logger.log( + `Compiler${name ? ` ${name}` : ""} is using config: ${configPath + .map((path) => `'${path}'`) + .join(", ")}`, + ); } }); diff --git a/packages/webpack-cli/src/types.ts b/packages/webpack-cli/src/types.ts index f74ebd1c2fa..ec31fa9c364 100644 --- a/packages/webpack-cli/src/types.ts +++ b/packages/webpack-cli/src/types.ts @@ -94,7 +94,7 @@ interface WebpackCLICommandOption extends CommanderOption { interface WebpackCLIConfig { options: WebpackConfiguration | WebpackConfiguration[]; - path: WeakMap; + path: WeakMap; } interface WebpackCLICommand extends Command { @@ -178,6 +178,7 @@ type WebpackDevServerOptions = DevServerConfig & config: string[]; configName?: string[]; disableInterpret?: boolean; + extends?: string[]; argv: Argv; }; @@ -186,8 +187,10 @@ type Callback = (...args: T) => void; /** * Webpack */ - -type WebpackConfiguration = Configuration; +type WebpackConfiguration = Configuration & { + // TODO add extends to webpack types + extends?: string | string[]; +}; type ConfigOptions = PotentialPromise; type CallableOption = (env: Env | undefined, argv: Argv) => WebpackConfiguration; type WebpackCompiler = Compiler | MultiCompiler; @@ -236,7 +239,7 @@ interface BasicPackageJsonContent { */ interface CLIPluginOptions { - configPath?: string; + configPath?: string[]; helpfulOutput: boolean; hot?: boolean | "only"; progress?: boolean | "profile"; diff --git a/packages/webpack-cli/src/webpack-cli.ts b/packages/webpack-cli/src/webpack-cli.ts index fcb5e2ab6b9..90c8f1ff402 100644 --- a/packages/webpack-cli/src/webpack-cli.ts +++ b/packages/webpack-cli/src/webpack-cli.ts @@ -975,6 +975,18 @@ class WebpackCLI implements IWebpackCLI { description: "Stop webpack-cli process with non-zero exit code on warnings from webpack", helpLevel: "minimum", }, + { + name: "extends", + alias: "e", + configs: [ + { + type: "string", + }, + ], + multiple: true, + description: "Extend webpack configuration", + helpLevel: "minimum", + }, ]; const minimumHelpFlags = [ @@ -1814,6 +1826,7 @@ class WebpackCLI implements IWebpackCLI { return { options, path: configPath }; }; + // TODO better name and better type const config: WebpackCLIConfig = { options: {} as WebpackConfiguration, path: new WeakMap(), @@ -1850,10 +1863,10 @@ class WebpackCLI implements IWebpackCLI { if (isArray) { (loadedConfig.options as ConfigOptions[]).forEach((options) => { - config.path.set(options, loadedConfig.path); + config.path.set(options, [loadedConfig.path]); }); } else { - config.path.set(loadedConfig.options, loadedConfig.path); + config.path.set(loadedConfig.options, [loadedConfig.path]); } }); @@ -1892,10 +1905,10 @@ class WebpackCLI implements IWebpackCLI { if (Array.isArray(config.options)) { config.options.forEach((item) => { - config.path.set(item, loadedConfig.path); + config.path.set(item, [loadedConfig.path]); }); } else { - config.path.set(loadedConfig.options, loadedConfig.path); + config.path.set(loadedConfig.options, [loadedConfig.path]); } } } @@ -1929,6 +1942,92 @@ class WebpackCLI implements IWebpackCLI { } } + const resolveExtends = async ( + config: WebpackConfiguration, + configPaths: WebpackCLIConfig["path"], + extendsPaths: string[], + ): Promise => { + delete config.extends; + + const loadedConfigs = await Promise.all( + extendsPaths.map((extendsPath) => + loadConfigByPath(path.resolve(extendsPath), options.argv), + ), + ); + + const merge = await this.tryRequireThenImport("webpack-merge"); + const loadedOptions = loadedConfigs.flatMap((config) => config.options); + + if (loadedOptions.length > 0) { + const prevPaths = configPaths.get(config); + const loadedPaths = loadedConfigs.flatMap((config) => config.path); + + if (prevPaths) { + const intersection = loadedPaths.filter((element) => prevPaths.includes(element)); + + if (intersection.length > 0) { + this.logger.error(`Recursive configuration detected, exiting.`); + process.exit(2); + } + } + + config = merge( + ...(loadedOptions as [WebpackConfiguration, ...WebpackConfiguration[]]), + config, + ); + + if (prevPaths) { + configPaths.set(config, [...prevPaths, ...loadedPaths]); + } + } + + if (config.extends) { + const extendsPaths = typeof config.extends === "string" ? [config.extends] : config.extends; + + config = await resolveExtends(config, configPaths, extendsPaths); + } + + return config; + }; + + // The `extends` param in CLI gets priority over extends in config file + if (options.extends && options.extends.length > 0) { + const extendsPaths = options.extends; + + if (Array.isArray(config.options)) { + config.options = await Promise.all( + config.options.map((options) => resolveExtends(options, config.path, extendsPaths)), + ); + } else { + // load the config from the extends option + config.options = await resolveExtends(config.options, config.path, extendsPaths); + } + } + // if no extends option is passed, check if the config file has extends + else if (Array.isArray(config.options) && config.options.some((options) => options.extends)) { + config.options = await Promise.all( + config.options.map((options) => { + if (options.extends) { + return resolveExtends( + options, + config.path, + typeof options.extends === "string" ? [options.extends] : options.extends, + ); + } else { + return options; + } + }), + ); + } else if (!Array.isArray(config.options) && config.options.extends) { + config.options = await resolveExtends( + config.options, + config.path, + typeof config.options.extends === "string" + ? [config.options.extends] + : config.options.extends, + ); + } + if (options.merge) { const merge = await this.tryRequireThenImport("webpack-merge"); @@ -1946,11 +2045,13 @@ class WebpackCLI implements IWebpackCLI { const configPath = config.path.get(options); const mergedOptions = merge(accumulator, options); - mergedConfigPaths.push(configPath as string); + if (configPath) { + mergedConfigPaths.push(...configPath); + } return mergedOptions; }, {}); - config.path.set(config.options, mergedConfigPaths as unknown as string); + config.path.set(config.options, mergedConfigPaths); } return config; diff --git a/test/build/extends/extends-cli-option/base.webpack.config.js b/test/build/extends/extends-cli-option/base.webpack.config.js new file mode 100644 index 00000000000..db299e40fa5 --- /dev/null +++ b/test/build/extends/extends-cli-option/base.webpack.config.js @@ -0,0 +1,9 @@ +module.exports = () => { + console.log("base.webpack.config.js"); + + return { + name: "base_config", + mode: "development", + entry: "./src/index.js", + }; +}; diff --git a/test/build/extends/extends-cli-option/deep.base.webpack.config.js b/test/build/extends/extends-cli-option/deep.base.webpack.config.js new file mode 100644 index 00000000000..46c91d0207f --- /dev/null +++ b/test/build/extends/extends-cli-option/deep.base.webpack.config.js @@ -0,0 +1,10 @@ +module.exports = () => { + console.log("deep.base.webpack.config.js"); + + return { + name: "base_config", + mode: "development", + entry: "./src/index.js", + bail: true, + }; +}; diff --git a/test/build/extends/extends-cli-option/src/index.js b/test/build/extends/extends-cli-option/src/index.js new file mode 100644 index 00000000000..26d7e0297e4 --- /dev/null +++ b/test/build/extends/extends-cli-option/src/index.js @@ -0,0 +1 @@ +console.log("i am index.js") diff --git a/test/build/extends/extends-cli-option/webpack.config.js b/test/build/extends/extends-cli-option/webpack.config.js new file mode 100644 index 00000000000..9fe563fec36 --- /dev/null +++ b/test/build/extends/extends-cli-option/webpack.config.js @@ -0,0 +1,9 @@ +const WebpackCLITestPlugin = require("../../../utils/webpack-cli-test-plugin"); + +module.exports = () => { + console.log("derived.webpack.config.js"); + + return { + plugins: [new WebpackCLITestPlugin()], + }; +}; diff --git a/test/build/extends/extends.test.js b/test/build/extends/extends.test.js new file mode 100644 index 00000000000..e3b6b3a735d --- /dev/null +++ b/test/build/extends/extends.test.js @@ -0,0 +1,136 @@ +"use strict"; + +const { run } = require("../../utils/test-utils"); + +describe("extends property", () => { + it("extends a provided webpack config correctly", async () => { + const { exitCode, stderr, stdout } = await run(__dirname + "/simple-case"); + + expect(exitCode).toBe(0); + expect(stderr).toBeFalsy(); + expect(stdout).toContain("base.webpack.config.js"); + expect(stdout).toContain("derived.webpack.config.js"); + expect(stdout).toContain("name: 'base_config'"); + expect(stdout).toContain("mode: 'development'"); + }); + + it("extends a provided array of webpack configs correctly", async () => { + const { exitCode, stderr, stdout } = await run(__dirname + "/multiple-extends"); + + expect(exitCode).toBe(0); + expect(stderr).toBeFalsy(); + expect(stdout).toContain("base1.webpack.config.js"); + expect(stdout).toContain("base2.webpack.config.js"); + expect(stdout).toContain("derived.webpack.config.js"); + expect(stdout).toContain("name: 'base_config2'"); + expect(stdout).toContain("mode: 'development'"); + }); + + it("extends a multilevel config correctly", async () => { + const { exitCode, stderr, stdout } = await run(__dirname + "/multi-level-extends"); + + expect(exitCode).toBe(0); + expect(stderr).toBeFalsy(); + expect(stdout).toContain("base1.webpack.config.js"); + expect(stdout).toContain("base2.webpack.config.js"); + expect(stdout).toContain("derived.webpack.config.js"); + expect(stdout).toContain("name: 'base_config1'"); + expect(stdout).toContain("mode: 'production'"); + }); + + it("extends a provided webpack config for multiple configs correctly", async () => { + const { exitCode, stderr, stdout } = await run(__dirname + "/multiple-configs"); + + expect(exitCode).toBe(0); + expect(stderr).toBeFalsy(); + expect(stdout).toContain("base.webpack.config.js"); + expect(stdout).toContain("derived.webpack.config.js"); + expect(stdout).toContain("name: 'derived_config1'"); + expect(stdout).toContain("name: 'derived_config2'"); + expect(stdout).not.toContain("name: 'base_config'"); + expect(stdout).toContain("mode: 'development'"); + expect(stdout).toContain("topLevelAwait: true"); + }); + + it("extends a provided webpack config for multiple configs correctly #2", async () => { + const { exitCode, stderr, stdout } = await run(__dirname + "/multiple-configs2"); + + expect(exitCode).toBe(0); + expect(stderr).toBeFalsy(); + expect(stdout).toContain("base.webpack.config.js"); + expect(stdout).toContain("derived.webpack.config.js"); + expect(stdout).toContain("name: 'base_config'"); + expect(stdout).toContain("name: 'derived_config2'"); + expect(stdout).toContain("mode: 'development'"); + expect(stdout).toContain("topLevelAwait: true"); + }); + + it("multiple extends a provided webpack config passed in the cli correctly", async () => { + const { exitCode, stderr, stdout } = await run(__dirname + "/extends-cli-option", [ + "--extends", + "./base.webpack.config.js", + "--extends", + "./deep.base.webpack.config.js", + ]); + + expect(exitCode).toBe(0); + expect(stderr).toBeFalsy(); + expect(stdout).toContain("derived.webpack.config.js"); + expect(stdout).toContain("base.webpack.config.js"); + expect(stdout).toContain("deep.base.webpack.config.js"); + expect(stdout).toContain("name: 'base_config'"); + expect(stdout).toContain("mode: 'development'"); + expect(stdout).toContain("bail: true"); + }); + + it("should work with multiple extends and multiple configuration", async () => { + const { exitCode, stderr, stdout } = await run(__dirname + "/multiple-configs1", [ + "--extends", + "./base.webpack.config.js", + "--extends", + "./other.config.js", + ]); + + expect(exitCode).toBe(0); + expect(stderr).toBeFalsy(); + expect(stdout).toContain("derived.webpack.config.js"); + expect(stdout).toContain("base.webpack.config.js"); + expect(stdout).toContain("other.config.js"); + expect(stdout).toContain("name: 'derived_config1'"); + expect(stdout).toContain("name: 'derived_config2'"); + expect(stdout).toContain("topLevelAwait: true"); + }); + + it("CLI `extends` should override `extends` in a configuration", async () => { + const { exitCode, stderr, stdout } = await run(__dirname + "/simple-case", [ + "--extends", + "./override.config.js", + ]); + + expect(exitCode).toBe(0); + expect(stderr).toBeFalsy(); + expect(stdout).toContain("override.config.js"); + expect(stdout).toContain("derived.webpack.config.js"); + expect(stdout).toContain("name: 'override_config'"); + expect(stdout).toContain("mode: 'development'"); + }); + + it("should throw an error on recursive", async () => { + const { exitCode, stderr, stdout } = await run(__dirname + "/recursive-extends"); + + expect(exitCode).toBe(2); + expect(stderr).toContain("Recursive configuration detected, exiting"); + expect(stdout).toBeFalsy(); + }); + + it("should throw an error on recursive #2", async () => { + const { exitCode, stderr, stdout } = await run(__dirname + "/recursive-extends", [ + "--config", + "other.config.js", + ]); + + expect(exitCode).toBe(2); + expect(stderr).toContain("Recursive configuration detected, exiting"); + expect(stdout).toBeFalsy(); + }); +}); diff --git a/test/build/extends/multi-level-extends/base1.webpack.config.js b/test/build/extends/multi-level-extends/base1.webpack.config.js new file mode 100644 index 00000000000..d9535e8ab71 --- /dev/null +++ b/test/build/extends/multi-level-extends/base1.webpack.config.js @@ -0,0 +1,13 @@ +module.exports = () => { + console.log("base1.webpack.config.js"); + + return { + name: "base_config1", + extends: ["./base2.webpack.config.js"], + mode: "production", + entry: "./src/index1.js", + output: { + filename: "bundle1.js", + }, + }; +}; diff --git a/test/build/extends/multi-level-extends/base2.webpack.config.js b/test/build/extends/multi-level-extends/base2.webpack.config.js new file mode 100644 index 00000000000..3e494c9e813 --- /dev/null +++ b/test/build/extends/multi-level-extends/base2.webpack.config.js @@ -0,0 +1,9 @@ +module.exports = () => { + console.log("base2.webpack.config.js"); + + return { + name: "base_config2", + mode: "development", + entry: "./src/index2.js", + }; +}; diff --git a/test/build/extends/multi-level-extends/src/index1.js b/test/build/extends/multi-level-extends/src/index1.js new file mode 100644 index 00000000000..7e6f6d3db95 --- /dev/null +++ b/test/build/extends/multi-level-extends/src/index1.js @@ -0,0 +1 @@ +console.log("i am index1"); diff --git a/test/build/extends/multi-level-extends/webpack.config.js b/test/build/extends/multi-level-extends/webpack.config.js new file mode 100644 index 00000000000..d5ffc2fc5f9 --- /dev/null +++ b/test/build/extends/multi-level-extends/webpack.config.js @@ -0,0 +1,10 @@ +const WebpackCLITestPlugin = require("../../../utils/webpack-cli-test-plugin"); + +module.exports = () => { + console.log("derived.webpack.config.js"); + + return { + extends: ["./base1.webpack.config.js"], + plugins: [new WebpackCLITestPlugin()], + }; +}; diff --git a/test/build/extends/multiple-configs/base.webpack.config.js b/test/build/extends/multiple-configs/base.webpack.config.js new file mode 100644 index 00000000000..f10862022b4 --- /dev/null +++ b/test/build/extends/multiple-configs/base.webpack.config.js @@ -0,0 +1,15 @@ +const WebpackCLITestPlugin = require("../../../utils/webpack-cli-test-plugin"); + +module.exports = () => { + console.log("base.webpack.config.js"); + + return { + name: "base_config", + mode: "development", + plugins: [new WebpackCLITestPlugin()], + + experiments: { + topLevelAwait: true, + }, + }; +}; diff --git a/test/build/extends/multiple-configs/other.config.js b/test/build/extends/multiple-configs/other.config.js new file mode 100644 index 00000000000..80c2fc96e94 --- /dev/null +++ b/test/build/extends/multiple-configs/other.config.js @@ -0,0 +1,11 @@ +module.exports = () => { + console.log("other.config.js"); + + return { + name: "other_config", + mode: "development", + experiments: { + topLevelAwait: true, + }, + }; +}; diff --git a/test/build/extends/multiple-configs/src/index1.js b/test/build/extends/multiple-configs/src/index1.js new file mode 100644 index 00000000000..9fc41fb4f1f --- /dev/null +++ b/test/build/extends/multiple-configs/src/index1.js @@ -0,0 +1 @@ +console.log("i am index1.js"); diff --git a/test/build/extends/multiple-configs/src/index2.js b/test/build/extends/multiple-configs/src/index2.js new file mode 100644 index 00000000000..7fa5b7a517e --- /dev/null +++ b/test/build/extends/multiple-configs/src/index2.js @@ -0,0 +1 @@ +console.log("i am index2.js"); diff --git a/test/build/extends/multiple-configs/webpack.config.js b/test/build/extends/multiple-configs/webpack.config.js new file mode 100644 index 00000000000..b2db2f158da --- /dev/null +++ b/test/build/extends/multiple-configs/webpack.config.js @@ -0,0 +1,16 @@ +module.exports = () => { + console.log("derived.webpack.config.js"); + + return [ + { + name: "derived_config1", + extends: "./base.webpack.config.js", + entry: "./src/index1.js", + }, + { + name: "derived_config2", + extends: "./base.webpack.config.js", + entry: "./src/index2.js", + }, + ]; +}; diff --git a/test/build/extends/multiple-configs1/base.webpack.config.js b/test/build/extends/multiple-configs1/base.webpack.config.js new file mode 100644 index 00000000000..f10862022b4 --- /dev/null +++ b/test/build/extends/multiple-configs1/base.webpack.config.js @@ -0,0 +1,15 @@ +const WebpackCLITestPlugin = require("../../../utils/webpack-cli-test-plugin"); + +module.exports = () => { + console.log("base.webpack.config.js"); + + return { + name: "base_config", + mode: "development", + plugins: [new WebpackCLITestPlugin()], + + experiments: { + topLevelAwait: true, + }, + }; +}; diff --git a/test/build/extends/multiple-configs1/other.config.js b/test/build/extends/multiple-configs1/other.config.js new file mode 100644 index 00000000000..80c2fc96e94 --- /dev/null +++ b/test/build/extends/multiple-configs1/other.config.js @@ -0,0 +1,11 @@ +module.exports = () => { + console.log("other.config.js"); + + return { + name: "other_config", + mode: "development", + experiments: { + topLevelAwait: true, + }, + }; +}; diff --git a/test/build/extends/multiple-configs1/src/index1.js b/test/build/extends/multiple-configs1/src/index1.js new file mode 100644 index 00000000000..9fc41fb4f1f --- /dev/null +++ b/test/build/extends/multiple-configs1/src/index1.js @@ -0,0 +1 @@ +console.log("i am index1.js"); diff --git a/test/build/extends/multiple-configs1/src/index2.js b/test/build/extends/multiple-configs1/src/index2.js new file mode 100644 index 00000000000..7fa5b7a517e --- /dev/null +++ b/test/build/extends/multiple-configs1/src/index2.js @@ -0,0 +1 @@ +console.log("i am index2.js"); diff --git a/test/build/extends/multiple-configs1/webpack.config.js b/test/build/extends/multiple-configs1/webpack.config.js new file mode 100644 index 00000000000..f12adb72cf6 --- /dev/null +++ b/test/build/extends/multiple-configs1/webpack.config.js @@ -0,0 +1,14 @@ +module.exports = () => { + console.log("derived.webpack.config.js"); + + return [ + { + name: "derived_config1", + entry: "./src/index1.js", + }, + { + name: "derived_config2", + entry: "./src/index2.js", + }, + ]; +}; diff --git a/test/build/extends/multiple-configs2/base.webpack.config.js b/test/build/extends/multiple-configs2/base.webpack.config.js new file mode 100644 index 00000000000..68ec8d384a4 --- /dev/null +++ b/test/build/extends/multiple-configs2/base.webpack.config.js @@ -0,0 +1,16 @@ +const WebpackCLITestPlugin = require("../../../utils/webpack-cli-test-plugin"); + +module.exports = () => { + console.log("base.webpack.config.js"); + + return { + entry: "./src/index1.js", + name: "base_config", + mode: "development", + plugins: [new WebpackCLITestPlugin()], + + experiments: { + topLevelAwait: true, + }, + }; +}; diff --git a/test/build/extends/multiple-configs2/src/index1.js b/test/build/extends/multiple-configs2/src/index1.js new file mode 100644 index 00000000000..9fc41fb4f1f --- /dev/null +++ b/test/build/extends/multiple-configs2/src/index1.js @@ -0,0 +1 @@ +console.log("i am index1.js"); diff --git a/test/build/extends/multiple-configs2/src/index2.js b/test/build/extends/multiple-configs2/src/index2.js new file mode 100644 index 00000000000..7fa5b7a517e --- /dev/null +++ b/test/build/extends/multiple-configs2/src/index2.js @@ -0,0 +1 @@ +console.log("i am index2.js"); diff --git a/test/build/extends/multiple-configs2/webpack.config.js b/test/build/extends/multiple-configs2/webpack.config.js new file mode 100644 index 00000000000..05b311b14e2 --- /dev/null +++ b/test/build/extends/multiple-configs2/webpack.config.js @@ -0,0 +1,17 @@ +const WebpackCLITestPlugin = require("../../../utils/webpack-cli-test-plugin"); + +module.exports = () => { + console.log("derived.webpack.config.js"); + + return [ + { + extends: "./base.webpack.config.js", + }, + { + name: "derived_config2", + mode: "development", + entry: "./src/index2.js", + plugins: [new WebpackCLITestPlugin()], + }, + ]; +}; diff --git a/test/build/extends/multiple-extends/base1.webpack.config.js b/test/build/extends/multiple-extends/base1.webpack.config.js new file mode 100644 index 00000000000..7fb6424a698 --- /dev/null +++ b/test/build/extends/multiple-extends/base1.webpack.config.js @@ -0,0 +1,9 @@ +module.exports = () => { + console.log("base1.webpack.config.js"); + + return { + name: "base_config1", + mode: "development", + entry: "./src/index.js", + }; +}; diff --git a/test/build/extends/multiple-extends/base2.webpack.config.js b/test/build/extends/multiple-extends/base2.webpack.config.js new file mode 100644 index 00000000000..7661abf08a7 --- /dev/null +++ b/test/build/extends/multiple-extends/base2.webpack.config.js @@ -0,0 +1,11 @@ +module.exports = () => { + console.log("base2.webpack.config.js"); + + return { + name: "base_config2", + entry: "./src/index2.js", + externals: { + jquery: "jQuery", + }, + }; +}; diff --git a/test/build/extends/multiple-extends/src/index2.js b/test/build/extends/multiple-extends/src/index2.js new file mode 100644 index 00000000000..8ba053a7356 --- /dev/null +++ b/test/build/extends/multiple-extends/src/index2.js @@ -0,0 +1 @@ +console.log("i am index2"); diff --git a/test/build/extends/multiple-extends/webpack.config.js b/test/build/extends/multiple-extends/webpack.config.js new file mode 100644 index 00000000000..20a16784aac --- /dev/null +++ b/test/build/extends/multiple-extends/webpack.config.js @@ -0,0 +1,10 @@ +const WebpackCLITestPlugin = require("../../../utils/webpack-cli-test-plugin"); + +module.exports = () => { + console.log("derived.webpack.config.js"); + + return { + extends: ["./base1.webpack.config.js", "./base2.webpack.config.js"], + plugins: [new WebpackCLITestPlugin()], + }; +}; diff --git a/test/build/extends/recursive-extends/other.config.js b/test/build/extends/recursive-extends/other.config.js new file mode 100644 index 00000000000..c918158aeea --- /dev/null +++ b/test/build/extends/recursive-extends/other.config.js @@ -0,0 +1,8 @@ +const WebpackCLITestPlugin = require("../../../utils/webpack-cli-test-plugin"); + +module.exports = () => { + return { + extends: "./webpack.config.js", + plugins: [new WebpackCLITestPlugin()], + }; +}; diff --git a/test/build/extends/recursive-extends/webpack.config.js b/test/build/extends/recursive-extends/webpack.config.js new file mode 100644 index 00000000000..c918158aeea --- /dev/null +++ b/test/build/extends/recursive-extends/webpack.config.js @@ -0,0 +1,8 @@ +const WebpackCLITestPlugin = require("../../../utils/webpack-cli-test-plugin"); + +module.exports = () => { + return { + extends: "./webpack.config.js", + plugins: [new WebpackCLITestPlugin()], + }; +}; diff --git a/test/build/extends/simple-case/base.webpack.config.js b/test/build/extends/simple-case/base.webpack.config.js new file mode 100644 index 00000000000..db299e40fa5 --- /dev/null +++ b/test/build/extends/simple-case/base.webpack.config.js @@ -0,0 +1,9 @@ +module.exports = () => { + console.log("base.webpack.config.js"); + + return { + name: "base_config", + mode: "development", + entry: "./src/index.js", + }; +}; diff --git a/test/build/extends/simple-case/override.config.js b/test/build/extends/simple-case/override.config.js new file mode 100644 index 00000000000..bf79ce64650 --- /dev/null +++ b/test/build/extends/simple-case/override.config.js @@ -0,0 +1,9 @@ +module.exports = () => { + console.log("override.config.js"); + + return { + name: "override_config", + mode: "development", + entry: "./src/index.js", + }; +}; diff --git a/test/build/extends/simple-case/src/index.js b/test/build/extends/simple-case/src/index.js new file mode 100644 index 00000000000..7a21c1b9d7d --- /dev/null +++ b/test/build/extends/simple-case/src/index.js @@ -0,0 +1 @@ +console.log("index.js") diff --git a/test/build/extends/simple-case/webpack.config.js b/test/build/extends/simple-case/webpack.config.js new file mode 100644 index 00000000000..2a761ad2b1a --- /dev/null +++ b/test/build/extends/simple-case/webpack.config.js @@ -0,0 +1,10 @@ +const WebpackCLITestPlugin = require("../../../utils/webpack-cli-test-plugin"); + +module.exports = () => { + console.log("derived.webpack.config.js"); + + return { + extends: "./base.webpack.config.js", + plugins: [new WebpackCLITestPlugin()], + }; +}; diff --git a/test/help/__snapshots__/help.test.js.snap.devServer4.webpack5 b/test/help/__snapshots__/help.test.js.snap.devServer4.webpack5 index 6bfca3640fc..d72de05f8db 100644 --- a/test/help/__snapshots__/help.test.js.snap.devServer4.webpack5 +++ b/test/help/__snapshots__/help.test.js.snap.devServer4.webpack5 @@ -105,6 +105,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -165,6 +166,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -225,6 +227,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -284,6 +287,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -331,6 +335,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -378,6 +383,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -425,6 +431,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -472,6 +479,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -519,6 +527,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -1500,6 +1509,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -1545,6 +1555,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -1590,6 +1601,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -1635,6 +1647,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -1680,6 +1693,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -1725,6 +1739,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -1771,6 +1786,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -1831,6 +1847,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -2081,6 +2098,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported. @@ -2139,6 +2157,7 @@ Options: --progress [value] Print compilation progress during build. -j, --json [value] Prints result as JSON or store it in a file. --fail-on-warnings Stop webpack-cli process with non-zero exit code on warnings from webpack + -e, --extends Extend webpack configuration -d, --devtool A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map). --no-devtool Negative 'devtool' option. --entry A module that is loaded upon startup. Only the last one is exported.