Skip to content

Commit 82b1fb7

Browse files
fix: support top multi compiler options (#2874)
1 parent 61726c1 commit 82b1fb7

File tree

4 files changed

+207
-104
lines changed

4 files changed

+207
-104
lines changed

packages/webpack-cli/lib/webpack-cli.js

+123-104
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,7 @@ class WebpackCLI {
847847
options.entry = [...entries, ...(options.entry || [])];
848848
}
849849

850-
await this.buildCommand(options, isWatchCommandUsed);
850+
await this.runWebpack(options, isWatchCommandUsed);
851851
},
852852
);
853853
} else if (isCommand(commandName, helpCommandOptions)) {
@@ -1521,107 +1521,124 @@ class WebpackCLI {
15211521
await this.program.parseAsync(args, parseOptions);
15221522
}
15231523

1524-
async resolveConfig(options) {
1525-
const loadConfig = async (configPath) => {
1526-
const { interpret } = this.utils;
1527-
const ext = path.extname(configPath);
1528-
const interpreted = Object.keys(interpret.jsVariants).find(
1529-
(variant) => variant === ext,
1530-
);
1524+
async loadConfig(configPath, argv = {}) {
1525+
const { interpret } = this.utils;
1526+
const ext = path.extname(configPath);
1527+
const interpreted = Object.keys(interpret.jsVariants).find((variant) => variant === ext);
15311528

1532-
if (interpreted) {
1533-
const { rechoir } = this.utils;
1534-
1535-
try {
1536-
rechoir.prepare(interpret.extensions, configPath);
1537-
} catch (error) {
1538-
if (error.failures) {
1539-
this.logger.error(`Unable load '${configPath}'`);
1540-
this.logger.error(error.message);
1541-
1542-
error.failures.forEach((failure) => {
1543-
this.logger.error(failure.error.message);
1544-
});
1545-
this.logger.error("Please install one of them");
1546-
process.exit(2);
1547-
}
1548-
1549-
this.logger.error(error);
1550-
process.exit(2);
1551-
}
1552-
}
1553-
1554-
let options;
1529+
if (interpreted) {
1530+
const { rechoir } = this.utils;
15551531

15561532
try {
1557-
options = await this.tryRequireThenImport(configPath, false);
1533+
rechoir.prepare(interpret.extensions, configPath);
15581534
} catch (error) {
1559-
this.logger.error(`Failed to load '${configPath}' config`);
1560-
1561-
if (this.isValidationError(error)) {
1535+
if (error.failures) {
1536+
this.logger.error(`Unable load '${configPath}'`);
15621537
this.logger.error(error.message);
1563-
} else {
1564-
this.logger.error(error);
1538+
1539+
error.failures.forEach((failure) => {
1540+
this.logger.error(failure.error.message);
1541+
});
1542+
this.logger.error("Please install one of them");
1543+
process.exit(2);
15651544
}
15661545

1546+
this.logger.error(error);
15671547
process.exit(2);
15681548
}
1549+
}
15691550

1570-
return { options, path: configPath };
1571-
};
1551+
let options;
15721552

1573-
const evaluateConfig = async (loadedConfig, argv) => {
1574-
const isMultiCompiler = Array.isArray(loadedConfig.options);
1575-
const config = isMultiCompiler ? loadedConfig.options : [loadedConfig.options];
1553+
try {
1554+
options = await this.tryRequireThenImport(configPath, false);
1555+
} catch (error) {
1556+
this.logger.error(`Failed to load '${configPath}' config`);
1557+
1558+
if (this.isValidationError(error)) {
1559+
this.logger.error(error.message);
1560+
} else {
1561+
this.logger.error(error);
1562+
}
15761563

1577-
const evaluatedConfig = await Promise.all(
1578-
config.map(async (rawConfig) => {
1579-
if (typeof rawConfig.then === "function") {
1580-
rawConfig = await rawConfig;
1564+
process.exit(2);
1565+
}
1566+
1567+
if (Array.isArray(options)) {
1568+
await Promise.all(
1569+
options.map(async (_, i) => {
1570+
if (typeof options[i].then === "function") {
1571+
options[i] = await options[i];
15811572
}
15821573

15831574
// `Promise` may return `Function`
1584-
if (typeof rawConfig === "function") {
1575+
if (typeof options[i] === "function") {
15851576
// when config is a function, pass the env from args to the config function
1586-
rawConfig = await rawConfig(argv.env, argv);
1577+
options[i] = await options[i](argv.env, argv);
15871578
}
1588-
1589-
return rawConfig;
15901579
}),
15911580
);
1581+
} else {
1582+
if (typeof options.then === "function") {
1583+
options = await options;
1584+
}
15921585

1593-
loadedConfig.options = isMultiCompiler ? evaluatedConfig : evaluatedConfig[0];
1586+
// `Promise` may return `Function`
1587+
if (typeof options === "function") {
1588+
// when config is a function, pass the env from args to the config function
1589+
options = await options(argv.env, argv);
1590+
}
1591+
}
15941592

1595-
const isObject = (value) => typeof value === "object" && value !== null;
1593+
const isObject = (value) => typeof value === "object" && value !== null;
15961594

1597-
if (!isObject(loadedConfig.options) && !Array.isArray(loadedConfig.options)) {
1598-
this.logger.error(`Invalid configuration in '${loadedConfig.path}'`);
1599-
process.exit(2);
1600-
}
1595+
if (!isObject(options) && !Array.isArray(options)) {
1596+
this.logger.error(`Invalid configuration in '${configPath}'`);
16011597

1602-
return loadedConfig;
1603-
};
1598+
process.exit(2);
1599+
}
16041600

1601+
return { options, path: configPath };
1602+
}
1603+
1604+
async resolveConfig(options) {
16051605
const config = { options: {}, path: new WeakMap() };
16061606

16071607
if (options.config && options.config.length > 0) {
1608-
const evaluatedConfigs = await Promise.all(
1609-
options.config.map(async (value) =>
1610-
evaluateConfig(await loadConfig(path.resolve(value)), options.argv || {}),
1608+
const loadedConfigs = await Promise.all(
1609+
options.config.map((configPath) =>
1610+
this.loadConfig(path.resolve(configPath), options.argv),
16111611
),
16121612
);
16131613

16141614
config.options = [];
16151615

1616-
evaluatedConfigs.forEach((evaluatedConfig) => {
1617-
if (Array.isArray(evaluatedConfig.options)) {
1618-
evaluatedConfig.options.forEach((options) => {
1619-
config.options.push(options);
1620-
config.path.set(options, evaluatedConfig.path);
1616+
loadedConfigs.forEach((loadedConfig) => {
1617+
const isArray = Array.isArray(loadedConfig.options);
1618+
1619+
// TODO we should run webpack multiple times when the `--config` options have multiple values with `--merge`, need to solve for the next major release
1620+
if (config.options.length === 0) {
1621+
config.options = loadedConfig.options;
1622+
} else {
1623+
if (!Array.isArray(config.options)) {
1624+
config.options = [config.options];
1625+
}
1626+
1627+
if (isArray) {
1628+
loadedConfig.options.forEach((item) => {
1629+
config.options.push(item);
1630+
});
1631+
} else {
1632+
config.options.push(loadedConfig.options);
1633+
}
1634+
}
1635+
1636+
if (isArray) {
1637+
loadedConfig.options.forEach((options) => {
1638+
config.path.set(options, loadedConfig.path);
16211639
});
16221640
} else {
1623-
config.options.push(evaluatedConfig.options);
1624-
config.path.set(evaluatedConfig.options, evaluatedConfig.path);
1641+
config.path.set(loadedConfig.options, loadedConfig.path);
16251642
}
16261643
});
16271644

@@ -1657,23 +1674,25 @@ class WebpackCLI {
16571674
}
16581675

16591676
if (foundDefaultConfigFile) {
1660-
const loadedConfig = await loadConfig(foundDefaultConfigFile.path);
1661-
const evaluatedConfig = await evaluateConfig(loadedConfig, options.argv || {});
1677+
const loadedConfig = await this.loadConfig(
1678+
foundDefaultConfigFile.path,
1679+
options.argv,
1680+
);
16621681

1663-
config.options = evaluatedConfig.options;
1682+
config.options = loadedConfig.options;
16641683

16651684
if (Array.isArray(config.options)) {
1666-
config.options.forEach((options) => {
1667-
config.path.set(options, evaluatedConfig.path);
1685+
config.options.forEach((item) => {
1686+
config.path.set(item, loadedConfig.path);
16681687
});
16691688
} else {
1670-
config.path.set(evaluatedConfig.options, evaluatedConfig.path);
1689+
config.path.set(loadedConfig.options, loadedConfig.path);
16711690
}
16721691
}
16731692
}
16741693

16751694
if (options.configName) {
1676-
const notfoundConfigNames = [];
1695+
const notFoundConfigNames = [];
16771696

16781697
config.options = options.configName.map((configName) => {
16791698
let found;
@@ -1685,15 +1704,15 @@ class WebpackCLI {
16851704
}
16861705

16871706
if (!found) {
1688-
notfoundConfigNames.push(configName);
1707+
notFoundConfigNames.push(configName);
16891708
}
16901709

16911710
return found;
16921711
});
16931712

1694-
if (notfoundConfigNames.length > 0) {
1713+
if (notFoundConfigNames.length > 0) {
16951714
this.logger.error(
1696-
notfoundConfigNames
1715+
notFoundConfigNames
16971716
.map(
16981717
(configName) =>
16991718
`Configuration with the name "${configName}" was not found.`,
@@ -1731,6 +1750,18 @@ class WebpackCLI {
17311750
return config;
17321751
}
17331752

1753+
runFunctionOnOptions(options, fn) {
1754+
if (Array.isArray(options)) {
1755+
for (let item of options) {
1756+
item = fn(item);
1757+
}
1758+
} else {
1759+
options = fn(options);
1760+
}
1761+
1762+
return options;
1763+
}
1764+
17341765
// TODO refactor
17351766
async applyOptions(config, options) {
17361767
if (options.analyze) {
@@ -1786,9 +1817,7 @@ class WebpackCLI {
17861817
return configOptions;
17871818
};
17881819

1789-
config.options = Array.isArray(config.options)
1790-
? config.options.map((options) => outputHints(options))
1791-
: outputHints(config.options);
1820+
this.runFunctionOnOptions(config.options, outputHints);
17921821

17931822
if (this.webpack.cli) {
17941823
const processArguments = (configOptions) => {
@@ -1850,9 +1879,7 @@ class WebpackCLI {
18501879
return configOptions;
18511880
};
18521881

1853-
config.options = Array.isArray(config.options)
1854-
? config.options.map((options) => processArguments(options))
1855-
: processArguments(config.options);
1882+
this.runFunctionOnOptions(config.options, processArguments);
18561883

18571884
const setupDefaultOptions = (configOptions) => {
18581885
// No need to run for webpack@4
@@ -1881,9 +1908,7 @@ class WebpackCLI {
18811908
return configOptions;
18821909
};
18831910

1884-
config.options = Array.isArray(config.options)
1885-
? config.options.map((options) => setupDefaultOptions(options))
1886-
: setupDefaultOptions(config.options);
1911+
this.runFunctionOnOptions(config.options, setupDefaultOptions);
18871912
}
18881913

18891914
// Logic for webpack@4
@@ -1943,12 +1968,10 @@ class WebpackCLI {
19431968
return configOptions;
19441969
};
19451970

1946-
config.options = Array.isArray(config.options)
1947-
? config.options.map((options) => processLegacyArguments(options))
1948-
: processLegacyArguments(config.options);
1971+
this.runFunctionOnOptions(config.options, processLegacyArguments);
19491972

19501973
// Apply `stats` and `stats.colors` options
1951-
const applyStatsColors = (configOptions) => {
1974+
const applyStatsOption = (configOptions) => {
19521975
// TODO remove after drop webpack@4
19531976
const statsForWebpack4 = this.webpack.Stats && this.webpack.Stats.presetToOptions;
19541977

@@ -2005,24 +2028,22 @@ class WebpackCLI {
20052028
return configOptions;
20062029
};
20072030

2008-
config.options = Array.isArray(config.options)
2009-
? config.options.map((options) => applyStatsColors(options))
2010-
: applyStatsColors(config.options);
2031+
this.runFunctionOnOptions(config.options, applyStatsOption);
20112032

20122033
return config;
20132034
}
20142035

20152036
async applyCLIPlugin(config, cliOptions) {
20162037
const CLIPlugin = await this.tryRequireThenImport("./plugins/CLIPlugin");
20172038

2018-
const addCLIPlugin = (configOptions) => {
2019-
if (!configOptions.plugins) {
2020-
configOptions.plugins = [];
2039+
const addCLIPlugin = (options) => {
2040+
if (!options.plugins) {
2041+
options.plugins = [];
20212042
}
20222043

2023-
configOptions.plugins.unshift(
2044+
options.plugins.unshift(
20242045
new CLIPlugin({
2025-
configPath: config.path.get(configOptions),
2046+
configPath: config.path.get(options),
20262047
helpfulOutput: !cliOptions.json,
20272048
hot: cliOptions.hot,
20282049
progress: cliOptions.progress,
@@ -2031,12 +2052,10 @@ class WebpackCLI {
20312052
}),
20322053
);
20332054

2034-
return configOptions;
2055+
return options;
20352056
};
20362057

2037-
config.options = Array.isArray(config.options)
2038-
? config.options.map((options) => addCLIPlugin(options))
2039-
: addCLIPlugin(config.options);
2058+
this.runFunctionOnOptions(config.options, addCLIPlugin);
20402059

20412060
return config;
20422061
}
@@ -2102,7 +2121,7 @@ class WebpackCLI {
21022121
return compiler;
21032122
}
21042123

2105-
async buildCommand(options, isWatchCommand) {
2124+
async runWebpack(options, isWatchCommand) {
21062125
// eslint-disable-next-line prefer-const
21072126
let compiler;
21082127
let createJsonStringifyStream;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
console.log(`test ${Math.random()}`);
2+
console.log(`test ${Math.random()}`);
3+
console.log(`test ${Math.random()}`);
4+
console.log(`test ${Math.random()}`);
5+
console.log(`test ${Math.random()}`);
6+
console.log(`test ${Math.random()}`);

0 commit comments

Comments
 (0)