Skip to content

Commit

Permalink
feat: add support to spawn multiple compilers with different configs (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
anshumanv committed Aug 25, 2020
1 parent ff0a657 commit c63ab29
Show file tree
Hide file tree
Showing 27 changed files with 84 additions and 16 deletions.
2 changes: 1 addition & 1 deletion packages/webpack-cli/README.md
Expand Up @@ -37,7 +37,7 @@ yarn add webpack-cli --dev

```
--entry string[] The entry point(s) of your application.
-c, --config string Provide path to a webpack configuration file
-c, --config string[] Provide path to webpack configuration file(s)
--config-name string[] Name of the configuration to use
-m, --merge string Merge a configuration file using webpack-merge
--progress Print compilation progress during build
Expand Down
49 changes: 37 additions & 12 deletions packages/webpack-cli/lib/groups/ConfigGroup.js
Expand Up @@ -143,18 +143,34 @@ class ConfigGroup extends GroupHelper {

async resolveConfigFiles() {
const { config, mode } = this.args;
if (config) {
const configPath = resolve(process.cwd(), config);
const configFiles = getConfigInfoFromFileName(configPath);
if (!configFiles.length) {
throw new ConfigError(`The specified config file doesn't exist in ${configPath}`);
if (config.length > 0) {
const resolvedOptions = [];
const finalizedConfigs = config.map(async (webpackConfig) => {
const configPath = resolve(webpackConfig);
const configFiles = getConfigInfoFromFileName(configPath);
if (!configFiles.length) {
throw new ConfigError(`The specified config file doesn't exist in ${configPath}`);
}
const foundConfig = configFiles[0];
const resolvedConfig = this.requireConfig(foundConfig);
return this.finalize(resolvedConfig);
});
// resolve all the configs
for await (const resolvedOption of finalizedConfigs) {
if (Array.isArray(resolvedOption.options)) {
resolvedOptions.push(...resolvedOption.options);
} else {
resolvedOptions.push(resolvedOption.options);
}
}
const foundConfig = configFiles[0];
const resolvedConfig = this.requireConfig(foundConfig);
this.opts = await this.finalize(resolvedConfig);
// When the resolved configs are more than 1, then pass them as Array [{...}, {...}] else pass the first config object {...}
const finalOptions = resolvedOptions.length > 1 ? resolvedOptions : resolvedOptions[0] || {};

this.opts['options'] = finalOptions;
return;
}

// When no config is supplied, lookup for default configs
const defaultConfigFiles = getDefaultConfigFiles();
const tmpConfigFiles = defaultConfigFiles.filter((file) => {
return existsSync(file.path);
Expand All @@ -175,9 +191,8 @@ class ConfigGroup extends GroupHelper {

async resolveConfigMerging() {
// eslint-disable-next-line no-prototype-builtins
if (Object.keys(this.args).some((arg) => arg === 'merge')) {
const { merge } = this.args;

const { merge } = this.args;
if (merge) {
// try resolving merge config
const newConfigPath = this.resolveFilePath(merge);

Expand All @@ -189,7 +204,17 @@ class ConfigGroup extends GroupHelper {
const foundConfig = configFiles[0];
const resolvedConfig = this.requireConfig(foundConfig);
const newConfigurationsObject = await this.finalize(resolvedConfig);
this.opts['options'] = webpackMerge(this.opts['options'], newConfigurationsObject.options);
let resolvedOptions = this.opts['options'];
let mergedOptions;
if (Array.isArray(resolvedOptions)) {
mergedOptions = [];
resolvedOptions.forEach((resolvedOption) => {
mergedOptions.push(webpackMerge(resolvedOption, newConfigurationsObject.options));
});
} else {
mergedOptions = webpackMerge(resolvedOptions, newConfigurationsObject.options);
}
this.opts['options'] = mergedOptions;
}
}

Expand Down
3 changes: 2 additions & 1 deletion packages/webpack-cli/lib/utils/cli-flags.js
Expand Up @@ -91,8 +91,9 @@ const core = [
usage: '--config <path to webpack configuration file>',
alias: 'c',
type: String,
defaultValue: null,
defaultValue: [],
group: CONFIG_GROUP,
multiple: true,
description: 'Provide path to a webpack configuration file e.g. ./webpack.config.js',
link: 'https://webpack.js.org/configuration/',
},
Expand Down
File renamed without changes.
Expand Up @@ -3,7 +3,7 @@ const { stat } = require('fs');
const { resolve } = require('path');
const { run } = require('../../../utils/test-utils');

describe('multiple config files', () => {
describe('Default configuration files: ', () => {
it('Uses prod config from dot folder if present', (done) => {
const { stdout, stderr } = run(__dirname, [], false);
expect(stderr).toBeFalsy();
Expand Down
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions test/config/multiple/init.js
@@ -0,0 +1 @@
console.log('Monkey D Luffy');
21 changes: 21 additions & 0 deletions test/config/multiple/multiple-config.test.js
@@ -0,0 +1,21 @@
const { existsSync } = require('fs');
const { resolve } = require('path');
// eslint-disable-next-line node/no-missing-require
const { run } = require('../../utils/test-utils');

describe('Multiple config flag: ', () => {
it('spawns multiple compilers for multiple configs', () => {
const { stdout, stderr, exitCode } = run(__dirname, ['-c', 'webpack1.config.js', '-c', 'webpack2.config.js'], false);
// Should contain the correct exit code
expect(exitCode).toEqual(0);
// Should spawn multiple compilers
expect(stdout).toContain('Child amd:');
expect(stdout).toContain('Child commonjs:');

expect(stderr).toBeFalsy();

// should generate the correct output files
expect(existsSync(resolve(__dirname, './dist/dist-commonjs.js'))).toBeTruthy();
expect(existsSync(resolve(__dirname, './dist/dist-amd.js'))).toBeTruthy();
});
});
10 changes: 10 additions & 0 deletions test/config/multiple/webpack1.config.js
@@ -0,0 +1,10 @@
module.exports = {
output: {
filename: './dist-amd.js',
libraryTarget: 'amd',
},
name: 'amd',
entry: './init.js',
mode: 'production',
devtool: 'eval-cheap-module-source-map',
};
10 changes: 10 additions & 0 deletions test/config/multiple/webpack2.config.js
@@ -0,0 +1,10 @@
module.exports = {
output: {
filename: './dist-commonjs.js',
libraryTarget: 'commonjs',
},
name: 'commonjs',
entry: './init.js',
mode: 'production',
target: 'node',
};
Expand Up @@ -8,7 +8,7 @@ describe('function configuration', () => {
const { stderr, stdout } = run(__dirname, ['--mode', 'development'], false);
expect(stderr).toBeFalsy();
expect(stdout).toBeTruthy();
expect(stdout).toContain("argv: { config: null, color: true, mode: 'development' }");
expect(stdout).toContain("argv: { config: [], color: true, mode: 'development' }");
// Should generate the appropriate files
expect(existsSync(resolve(__dirname, './dist/dev.js'))).toBeTruthy();
});
Expand Down

0 comments on commit c63ab29

Please sign in to comment.