Skip to content

Commit

Permalink
feat: allow passing strings in env flag (#1939)
Browse files Browse the repository at this point in the history
  • Loading branch information
anshumanv authored Oct 16, 2020
1 parent 97557bf commit cc081a2
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 14 deletions.
12 changes: 1 addition & 11 deletions packages/webpack-cli/lib/groups/ConfigGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,17 +167,7 @@ const finalize = async (moduleObj, args) => {
// `Promise` may return `Function`
if (typeof rawConfig === 'function') {
// when config is a function, pass the env from args to the config function
let envs;

if (Array.isArray(env)) {
envs = env.reduce((envObject, envOption) => {
envObject[envOption] = true;

return envObject;
}, {});
}

rawConfig = await rawConfig(envs, args);
rawConfig = await rawConfig(env, args);
}

return rawConfig;
Expand Down
22 changes: 22 additions & 0 deletions packages/webpack-cli/lib/utils/arg-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,28 @@ const argParser = (options, args, argsOnly = false, name = '') => {
// a multiple argument parsing function
const multiArg = (value, previous = []) => previous.concat([value]);
parserInstance.option(flagsWithType, option.description, multiArg, option.defaultValue).action(() => {});
} else if (option.multipleType) {
// for options which accept multiple types like env
// so you can do `--env platform=staging --env production`
// { platform: "staging", production: true }
const multiArg = (value, previous = {}) => {
// this ensures we're only splitting by the first `=`
const [allKeys, val] = value.split(/=(.+)/, 2);
const splitKeys = allKeys.split(/\.(?!$)/);
let prevRef = previous;
splitKeys.forEach((someKey, index) => {
if (!prevRef[someKey]) prevRef[someKey] = {};
if ('string' === typeof prevRef[someKey]) {
prevRef[someKey] = {};
}
if (index === splitKeys.length - 1) {
prevRef[someKey] = val || true;
}
prevRef = prevRef[someKey];
});
return previous;
};
parserInstance.option(flagsWithType, option.description, multiArg, option.defaultValue).action(() => {});
} else {
// Prevent default behavior for standalone options
parserInstance.option(flagsWithType, option.description, option.defaultValue).action(() => {});
Expand Down
2 changes: 1 addition & 1 deletion packages/webpack-cli/lib/utils/cli-flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ const core = [
name: 'env',
usage: '--env',
type: String,
multiple: true,
multipleType: true,
description: 'Environment passed to the configuration when it is a function',
},
{
Expand Down
63 changes: 63 additions & 0 deletions test/config/type/function-with-env/function-with-env.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ const { resolve } = require('path');
const { run } = require('../../../utils/test-utils');

describe('function configuration', () => {
it('should throw when env is not supplied', () => {
const { stderr, stdout, exitCode } = run(__dirname, ['--env'], false);
expect(stdout).toBeFalsy();
expect(stderr).toBeTruthy();
expect(stderr).toContain(`option '--env <value>' argument missing`);
expect(exitCode).toEqual(1);
});
it('is able to understand a configuration file as a function', () => {
const { stderr, stdout } = run(__dirname, ['--env', 'isProd']);
expect(stderr).toBeFalsy();
Expand All @@ -18,6 +25,62 @@ describe('function configuration', () => {
// Should generate the appropriate files
expect(existsSync(resolve(__dirname, './bin/dev.js'))).toBeTruthy();
});
it('Supports passing string in env', () => {
const { stderr, stdout } = run(__dirname, [
'--env',
'environment=production',
'--env',
'app.title=Luffy',
'-c',
'webpack.env.config.js',
]);
expect(stderr).toBeFalsy();
expect(stdout).toBeTruthy();
// Should generate the appropriate files
expect(existsSync(resolve(__dirname, './bin/Luffy.js'))).toBeTruthy();
});
it('Supports long nested values in env', () => {
const { stderr, stdout } = run(__dirname, [
'--env',
'file.name.is.this=Atsumu',
'--env',
'environment=production',
'-c',
'webpack.env.config.js',
]);
expect(stderr).toBeFalsy();
expect(stdout).toBeTruthy();
// Should generate the appropriate files
expect(existsSync(resolve(__dirname, './bin/Atsumu.js'))).toBeTruthy();
});
it('Supports multiple equal in a string', () => {
const { stderr, stdout } = run(__dirname, [
'--env',
'file=name=is=Eren',
'--env',
'environment=multipleq',
'-c',
'webpack.env.config.js',
]);
expect(stderr).toBeFalsy();
expect(stdout).toBeTruthy();
// Should generate the appropriate files
expect(existsSync(resolve(__dirname, './bin/name=is=Eren.js'))).toBeTruthy();
});
it('Supports dot at the end', () => {
const { stderr, stdout } = run(__dirname, ['--env', 'name.=Hisoka', '--env', 'environment=dot', '-c', 'webpack.env.config.js']);
expect(stderr).toBeFalsy();
expect(stdout).toBeTruthy();
// Should generate the appropriate files
expect(existsSync(resolve(__dirname, './bin/Hisoka.js'))).toBeTruthy();
});
it('Supports dot at the end', () => {
const { stderr, stdout } = run(__dirname, ['--env', 'name.', '--env', 'environment=dot', '-c', 'webpack.env.config.js']);
expect(stderr).toBeFalsy();
expect(stdout).toBeTruthy();
// Should generate the appropriate files
expect(existsSync(resolve(__dirname, './bin/true.js'))).toBeTruthy();
});
it('is able to understand multiple env flags', (done) => {
const { stderr, stdout } = run(__dirname, ['--env', 'isDev', '--env', 'verboseStats', '--env', 'envMessage']);
expect(stderr).toBeFalsy();
Expand Down
32 changes: 32 additions & 0 deletions test/config/type/function-with-env/webpack.env.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module.exports = (env) => {
const { environment, app, file } = env;
const customName = file && file.name && file.name.is && file.name.is.this;
const appTitle = app && app.title;
if (environment === 'production') {
return {
entry: './a.js',
output: {
filename: `${customName ? customName : appTitle}.js`,
},
};
}
if (environment === 'multipleq') {
const { file } = env;
return {
entry: './a.js',
output: {
filename: `${file}.js`,
},
};
}
if (environment === 'dot') {
const file = env['name.'];
return {
entry: './a.js',
output: {
filename: `${file}.js`,
},
};
}
return {};
};
2 changes: 0 additions & 2 deletions test/config/type/promise-function/promise-function.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ const { run } = require('../../../utils/test-utils');
describe('promise function', () => {
it('is able to understand a configuration file as a promise', (done) => {
const { stdout, stderr } = run(__dirname, ['-c', './webpack.config.js'], false);
console.log(stdout);
console.log(stderr);
expect(stdout).toBeTruthy();
expect(stderr).toBeFalsy();
stat(resolve(__dirname, './binary/promise.js'), (err, stats) => {
Expand Down

0 comments on commit cc081a2

Please sign in to comment.