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

feat: add support to spawn multiple compilers with different configs #1765

Merged
merged 9 commits into from Aug 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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}`);
anshumanv marked this conversation as resolved.
Show resolved Hide resolved
}
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: [],
anshumanv marked this conversation as resolved.
Show resolved Hide resolved
anshumanv marked this conversation as resolved.
Show resolved Hide resolved
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
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