From 31411d0a9f640460cd8d7757ef5e90d22016faa5 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Wed, 18 Mar 2020 15:47:02 +0530 Subject: [PATCH 01/15] chore: use commander --- packages/webpack-cli/lib/bootstrap.js | 27 ++++--------- packages/webpack-cli/lib/utils/arg-parser.js | 41 ++++++++++++++++++++ packages/webpack-cli/lib/webpack-cli.js | 15 +++++-- packages/webpack-cli/package.json | 1 + 4 files changed, 62 insertions(+), 22 deletions(-) create mode 100644 packages/webpack-cli/lib/utils/arg-parser.js diff --git a/packages/webpack-cli/lib/bootstrap.js b/packages/webpack-cli/lib/bootstrap.js index f014721148f..8f7733f2ec2 100644 --- a/packages/webpack-cli/lib/bootstrap.js +++ b/packages/webpack-cli/lib/bootstrap.js @@ -2,7 +2,7 @@ const WebpackCLI = require('./webpack-cli'); const { core, commands } = require('./utils/cli-flags'); const logger = require('./utils/logger'); const cliExecuter = require('./utils/cli-executer'); - +const argParser = require('./utils/arg-parser'); require('./utils/process-log'); process.title = 'webpack-cli'; @@ -21,7 +21,7 @@ const isCommandUsed = commands => }); const resolveNegatedArgs = args => { - args._unknown.forEach((arg, idx) => { + args.forEach((arg, idx) => { if (arg.includes('--') || arg.includes('--no')) { const argPair = arg.split('='); const optName = arg.includes('--no') ? argPair[0].slice(5) : argPair[0].slice(2); @@ -36,24 +36,14 @@ const resolveNegatedArgs = args => { if (cliFlag) { args[cliFlag.group][optName] = argValue; args._all[optName] = argValue; - args._unknown[idx] = null; + args.args[idx] = null; } } }); }; async function runCLI(cli, commandIsUsed) { - let args; - const helpFlagExists = isFlagPresent(process.argv, 'help'); - const versionFlagExists = isFlagPresent(process.argv, 'version'); - - if (helpFlagExists) { - cli.runHelp(process.argv); - return; - } else if (versionFlagExists) { - cli.runVersion(); - return; - } + const parsedArgs = argParser('webpack', core, process.argv, cli.runHelp, cli.runVersion); if (commandIsUsed) { commandIsUsed.defaultOption = true; @@ -61,10 +51,9 @@ async function runCLI(cli, commandIsUsed) { return await cli.runCommand(commandIsUsed, ...args); } else { try { - args = cli.commandLineArgs(core, { stopAtFirstUnknown: false, partial: true }); - if (args._unknown) { - resolveNegatedArgs(args); - args._unknown + if (parsedArgs.args.length > 0) { + resolveNegatedArgs(parsedArgs.args); + parsedArgs.args .filter(e => e) .forEach(unknown => { logger.warn('Unknown argument:', unknown); @@ -72,7 +61,7 @@ async function runCLI(cli, commandIsUsed) { cliExecuter(); return; } - const result = await cli.run(args, core); + const result = await cli.run(parsedArgs.opts(), core); if (!result) { return; } diff --git a/packages/webpack-cli/lib/utils/arg-parser.js b/packages/webpack-cli/lib/utils/arg-parser.js new file mode 100644 index 00000000000..0ccd86f9a26 --- /dev/null +++ b/packages/webpack-cli/lib/utils/arg-parser.js @@ -0,0 +1,41 @@ +const commander = require("commander"); + +/** + * Creates Argument parser corresponding to the supplied options + * parse the args and return the result + * + * @param {object[]} options Array of objects with details about flags + * @param {string[]} args process.argv or it's subset + */ +function argParser(name, options, args, helpFunction, versionFunction) { + const parser = new commander.Command(); + // Set parser name + parser.name(name); + + // Use customized version output + parser.on('option:version', () => { + versionFunction(args); + process.exit(0); + }); + + // Use customised help output + parser.on('option:help', () => { + helpFunction(args); + process.exit(0); + }); + + // Allow execution if unknown arguments are present + parser.allowUnknownOption(true); + + // Register options on the parser + options.reduce((parserInstance, option) => { + const flags = option.alias ? `-${option.alias}, --${option.name}` : `--${option.name}`; + const flagsWithType = option.type !== Boolean ? flags + ' [type]' : flags; + parserInstance.option(flagsWithType, option.description, option.defaultValue); + return parserInstance; + }, parser); + + return parser.parse(args); +} + +module.exports = argParser; diff --git a/packages/webpack-cli/lib/webpack-cli.js b/packages/webpack-cli/lib/webpack-cli.js index 9c6fa362b14..a98153c25d2 100644 --- a/packages/webpack-cli/lib/webpack-cli.js +++ b/packages/webpack-cli/lib/webpack-cli.js @@ -36,12 +36,12 @@ class WebpackCLI extends GroupHelper { this.outputConfiguration = {}; } setMappedGroups(args, inlineOptions) { - const { _all } = args; - Object.keys(_all).forEach(key => { - this.setGroupMap(key, _all[key], inlineOptions); + Object.keys(args).forEach(key => { + this.setGroupMap(this._toKebabCase(key), args[key], inlineOptions); }); } setGroupMap(key, val, inlineOptions) { + if (val === undefined) return; const opt = inlineOptions.find(opt => opt.name === key); const groupName = opt.group; if (this.groupMap.has(groupName)) { @@ -91,6 +91,15 @@ class WebpackCLI extends GroupHelper { getCoreFlags() { return core; } + + /** + * Convert camelcase to kebabcase + * @param {string} string + */ + _toKebabCase(string) { + return string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); + } + /** * Based on the parsed keys, the function will import and create * a group that handles respective values diff --git a/packages/webpack-cli/package.json b/packages/webpack-cli/package.json index 45cbb4edd17..ed170589729 100644 --- a/packages/webpack-cli/package.json +++ b/packages/webpack-cli/package.json @@ -29,6 +29,7 @@ "chalk": "^3.0.0", "command-line-args": "^5.1.1", "command-line-usage": "^6.1.0", + "commander": "^5.0.0", "enquirer": "^2.3.4", "execa": "^3.2.0", "import-local": "^3.0.2", From 7afa0e1f0149f5e67be90fa941aff28f9c923523 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Wed, 18 Mar 2020 16:25:11 +0530 Subject: [PATCH 02/15] chore: add support for help and version command --- packages/webpack-cli/lib/bootstrap.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/webpack-cli/lib/bootstrap.js b/packages/webpack-cli/lib/bootstrap.js index 8f7733f2ec2..9ce7849c311 100644 --- a/packages/webpack-cli/lib/bootstrap.js +++ b/packages/webpack-cli/lib/bootstrap.js @@ -45,6 +45,16 @@ const resolveNegatedArgs = args => { async function runCLI(cli, commandIsUsed) { const parsedArgs = argParser('webpack', core, process.argv, cli.runHelp, cli.runVersion); + if (parsedArgs.args.includes('help')) { + cli.runHelp(process.argv); + process.exit(0); + } + + if (parsedArgs.args.includes('version')) { + cli.runVersion(); + process.exit(0); + } + if (commandIsUsed) { commandIsUsed.defaultOption = true; args = normalizeFlags(process.argv, commandIsUsed); From 2e5205383f89dd27580afeda81eb2e4900febb72 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Wed, 18 Mar 2020 16:49:06 +0530 Subject: [PATCH 03/15] chore: remove duplicate code for no-mode --- packages/webpack-cli/lib/groups/ZeroConfigGroup.js | 7 +------ test/no-mode/no-mode.test.js | 4 ++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/webpack-cli/lib/groups/ZeroConfigGroup.js b/packages/webpack-cli/lib/groups/ZeroConfigGroup.js index 1d0e36f2c65..41048e021d6 100644 --- a/packages/webpack-cli/lib/groups/ZeroConfigGroup.js +++ b/packages/webpack-cli/lib/groups/ZeroConfigGroup.js @@ -20,7 +20,7 @@ class ZeroConfigGroup extends GroupHelper { if (process.env.NODE_ENV && (process.env.NODE_ENV === PRODUCTION || process.env.NODE_ENV === DEVELOPMENT)) { return process.env.NODE_ENV; } else { - if ((this.args.mode || this.args.noMode) && (this.args.dev || this.args.prod)) { + if ((this.args.mode !== undefined ) && (this.args.dev || this.args.prod)) { logger.warn( `You provided both ${this.args.mode ? 'mode' : 'no-mode'} and ${ this.args.prod ? '--prod' : '--dev' @@ -32,11 +32,6 @@ class ZeroConfigGroup extends GroupHelper { return NONE ; } } - if (this.args.noMode && this.args.mode) { - logger.warn( - 'You Provided both mode and no-mode arguments. You Should Provide just one. "mode" will be used.' - ) - } if (this.args.mode) { return this.args.mode; } diff --git a/test/no-mode/no-mode.test.js b/test/no-mode/no-mode.test.js index c043e9f4740..762716c633f 100644 --- a/test/no-mode/no-mode.test.js +++ b/test/no-mode/no-mode.test.js @@ -40,7 +40,7 @@ describe('no-mode flag', () => { it('should load a production config when --mode=production & --no-mode are passed', done => { const { stderr, stdout } = run(__dirname, ['--mode', 'production', '--no-mode']); - expect(stderr).toContain('"mode" will be used'); + expect(stderr).toBeFalsy(); expect(stdout).toBeTruthy(); stat(resolve(__dirname, './bin/main.js'), (err, stats) => { @@ -52,7 +52,7 @@ describe('no-mode flag', () => { it('should load a development config when --mode=development and --no-mode are passed', done => { const { stderr, stdout } = run(__dirname, ['--mode', 'development', '--no-mode']); - expect(stderr).toContain('"mode" will be used'); + expect(stderr).toBeFalsy(); expect(stdout).toBeTruthy(); stat(resolve(__dirname, './bin/main.js'), (err, stats) => { From cfc5978ec9805295254dc4291749d28a7734e5d5 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Wed, 18 Mar 2020 16:55:25 +0530 Subject: [PATCH 04/15] chore: create helpers --- packages/webpack-cli/lib/utils/helpers.js | 10 ++++++++++ packages/webpack-cli/lib/webpack-cli.js | 11 ++--------- 2 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 packages/webpack-cli/lib/utils/helpers.js diff --git a/packages/webpack-cli/lib/utils/helpers.js b/packages/webpack-cli/lib/utils/helpers.js new file mode 100644 index 00000000000..34fdd0a55d4 --- /dev/null +++ b/packages/webpack-cli/lib/utils/helpers.js @@ -0,0 +1,10 @@ +/** + * Convert camelCase to kebab-case + * @param {string} str input string in camelCase + * @returns {string} output string in kebab-case + */ +function toKebabCase(str) { + return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() +} + +module.exports = { toKebabCase }; diff --git a/packages/webpack-cli/lib/webpack-cli.js b/packages/webpack-cli/lib/webpack-cli.js index a98153c25d2..e439b0c24f8 100644 --- a/packages/webpack-cli/lib/webpack-cli.js +++ b/packages/webpack-cli/lib/webpack-cli.js @@ -5,7 +5,7 @@ const { Compiler } = require('./utils/Compiler'); const { groups, core } = require('./utils/cli-flags'); const webpackMerge = require('webpack-merge'); const commandArgs = require('command-line-args'); - +const { toKebabCase } = require('./utils/helpers'); const defaultCommands = { init: 'init', loader: 'generate-loader', @@ -37,7 +37,7 @@ class WebpackCLI extends GroupHelper { } setMappedGroups(args, inlineOptions) { Object.keys(args).forEach(key => { - this.setGroupMap(this._toKebabCase(key), args[key], inlineOptions); + this.setGroupMap(toKebabCase(key), args[key], inlineOptions); }); } setGroupMap(key, val, inlineOptions) { @@ -92,13 +92,6 @@ class WebpackCLI extends GroupHelper { return core; } - /** - * Convert camelcase to kebabcase - * @param {string} string - */ - _toKebabCase(string) { - return string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); - } /** * Based on the parsed keys, the function will import and create From 8338caecbf8ae7547488e48debe2479f64664667 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Thu, 19 Mar 2020 14:55:37 +0530 Subject: [PATCH 05/15] chore: remove global flag --- .../webpack-cli/lib/groups/AdvancedGroup.js | 53 ------------------- packages/webpack-cli/lib/utils/cli-flags.js | 9 ---- test/global/global.test.js | 53 ------------------- test/global/global1.js | 1 - test/global/global2.js | 1 - test/global/index.js | 5 -- 6 files changed, 122 deletions(-) delete mode 100644 test/global/global.test.js delete mode 100644 test/global/global1.js delete mode 100644 test/global/global2.js delete mode 100644 test/global/index.js diff --git a/packages/webpack-cli/lib/groups/AdvancedGroup.js b/packages/webpack-cli/lib/groups/AdvancedGroup.js index c3abafb23e4..98dea3e4e4b 100644 --- a/packages/webpack-cli/lib/groups/AdvancedGroup.js +++ b/packages/webpack-cli/lib/groups/AdvancedGroup.js @@ -77,59 +77,6 @@ class AdvancedGroup extends GroupHelper { if (args.target) { options.target = args.target; } - - if (args.global) { - const globalArrLen = args.global.length; - if (!globalArrLen) { - logger.warn('Argument to global flag is none'); - return; - } - if (globalArrLen === 1) { - logger.warn('Argument to global flag expected a key/value pair'); - return; - } - - const providePluginObject = {}; - args.global.forEach((arg, idx) => { - const isKey = idx % 2 === 0; - const isConcatArg = arg.includes('='); - if (isKey && isConcatArg) { - const splitIdx = arg.indexOf('='); - const argVal = arg.substr(splitIdx + 1); - const argKey = arg.substr(0, splitIdx); - if (!argVal.length) { - logger.warn(`Found unmatching value for global flag key '${argKey}'`); - return; - } - // eslint-disable-next-line no-prototype-builtins - if (providePluginObject.hasOwnProperty(argKey)) { - logger.warn(`Overriding key '${argKey}' for global flag`); - } - providePluginObject[argKey] = argVal; - return; - } - if (isKey) { - const nextArg = args.global[idx + 1]; - // eslint-disable-next-line no-prototype-builtins - if (providePluginObject.hasOwnProperty(arg)) { - logger.warn(`Overriding key '${arg}' for global flag`); - } - if (!nextArg) { - logger.warn(`Found unmatching value for global flag key '${arg}'`); - return; - } - providePluginObject[arg] = nextArg; - } - }); - - const { ProvidePlugin } = require('webpack'); - const globalVal = new ProvidePlugin(providePluginObject); - if (options && options.plugins) { - options.plugins.unshift(globalVal); - } else { - options.plugins = [globalVal]; - } - } } run() { this.resolveOptions(); diff --git a/packages/webpack-cli/lib/utils/cli-flags.js b/packages/webpack-cli/lib/utils/cli-flags.js index dc90ea2873c..063c12f290a 100644 --- a/packages/webpack-cli/lib/utils/cli-flags.js +++ b/packages/webpack-cli/lib/utils/cli-flags.js @@ -197,15 +197,6 @@ module.exports = { description: 'Load a given plugin', link: 'https://webpack.js.org/plugins/', }, - { - name: 'global', - usage: '--global myVar ./global.js', - alias: 'g', - type: String, - multiple: true, - group: ADVANCED_GROUP, - description: 'Declares and exposes a global variable', - }, { name: 'target', alias: 't', diff --git a/test/global/global.test.js b/test/global/global.test.js deleted file mode 100644 index 3e284d1df01..00000000000 --- a/test/global/global.test.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict'; - -const path = require('path'); -const execa = require('execa'); -const { sync: spawnSync } = execa; - -const { run } = require('../utils/test-utils'); - -describe('global flag', () => { - it('warns if there are no arguments to flag', () => { - const { stderr } = run(__dirname, ['--global']); - expect(stderr).toContain('Argument to global flag is none'); - }); - - it('warns if there are no value for key', () => { - const { stderr } = run(__dirname, ['--global', 'myVar']); - expect(stderr).toContain('Argument to global flag expected a key/value pair'); - }); - - it('is able to inject one variable to global scope', () => { - const { stdout } = run(__dirname, ['--global', 'myVar', './global1.js']); - expect(stdout).toContain('option has not been set, webpack will fallback to'); - const executable = path.join(__dirname, './bin/main.js'); - const bundledScript = spawnSync('node', [executable]); - expect(bundledScript.stdout).toEqual('myVar ./global1.js'); - }); - - it('is able to inject multiple variables to global scope', () => { - const { stdout } = run(__dirname, ['--global', 'myVar', './global1.js', '--global', 'myVar2', './global2.js']); - expect(stdout).toContain('option has not been set, webpack will fallback to'); - const executable = path.join(__dirname, './bin/main.js'); - const bundledScript = spawnSync('node', [executable]); - expect(bundledScript.stdout).toEqual('myVar ./global1.js\nmyVar ./global2.js'); - }); - - it('understands = syntax', () => { - const { stdout } = run(__dirname, ['--global', 'myVar', './global1.js', '--global', 'myVar2=./global2.js']); - expect(stdout).toContain('option has not been set, webpack will fallback to'); - const executable = path.join(__dirname, './bin/main.js'); - const bundledScript = spawnSync('node', [executable]); - expect(bundledScript.stdout).toEqual('myVar ./global1.js\nmyVar ./global2.js'); - }); - - it('warns on multiple flags that are inconsistent', () => { - const result = run(__dirname, ['--global', 'myVar', './global1.js', '--global', 'myVar2']); - // eslint-disable-next-line - expect(result.stderr).toContain("Found unmatching value for global flag key 'myVar2'"); - - const result2 = run(__dirname, ['--global', 'myVar', './global1.js', '--global', 'myVar2=']); - // eslint-disable-next-line - expect(result2.stderr).toContain("Found unmatching value for global flag key 'myVar2'"); - }); -}); diff --git a/test/global/global1.js b/test/global/global1.js deleted file mode 100644 index e7d024ed70b..00000000000 --- a/test/global/global1.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = 'myVar ./global1.js'; diff --git a/test/global/global2.js b/test/global/global2.js deleted file mode 100644 index c80fbb2b620..00000000000 --- a/test/global/global2.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = 'myVar ./global2.js'; diff --git a/test/global/index.js b/test/global/index.js deleted file mode 100644 index c832cbbeaeb..00000000000 --- a/test/global/index.js +++ /dev/null @@ -1,5 +0,0 @@ -console.log(myVar); - -try { - console.log(myVar2); -} catch(e) {} From ba83fa061bff3ef169a37a763116385824d35007 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Thu, 19 Mar 2020 15:43:26 +0530 Subject: [PATCH 06/15] chore: improve arg parsing and tests --- packages/webpack-cli/lib/groups/StatsGroup.js | 3 +++ packages/webpack-cli/lib/groups/ZeroConfigGroup.js | 5 +++++ packages/webpack-cli/lib/utils/cli-flags.js | 9 +-------- test/config/basic/basic-config.test.js | 2 +- test/entry/defaults-index/entry-multi-args.test.js | 2 +- test/stats/stats.test.js | 2 +- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/webpack-cli/lib/groups/StatsGroup.js b/packages/webpack-cli/lib/groups/StatsGroup.js index 1091dd2d288..a3cd98e52ff 100644 --- a/packages/webpack-cli/lib/groups/StatsGroup.js +++ b/packages/webpack-cli/lib/groups/StatsGroup.js @@ -23,6 +23,9 @@ class StatsGroup extends GroupHelper { this.opts.option.stats = { verbose: true, }; + } else if (!StatsGroup.validOptions().includes(this.args.stats)) { + logger.warn(`'${this.args.stats}' is invalid value for stats. Using 'normal' option for stats`); + this.opts.options.stats = 'normal'; } else { this.opts.options.stats = this.args.stats; } diff --git a/packages/webpack-cli/lib/groups/ZeroConfigGroup.js b/packages/webpack-cli/lib/groups/ZeroConfigGroup.js index 41048e021d6..55033fb4f6e 100644 --- a/packages/webpack-cli/lib/groups/ZeroConfigGroup.js +++ b/packages/webpack-cli/lib/groups/ZeroConfigGroup.js @@ -32,7 +32,12 @@ class ZeroConfigGroup extends GroupHelper { return NONE ; } } + if (this.args.mode) { + if (this.args.mode !== PRODUCTION && this.args.mode !== DEVELOPMENT && this.args.mode !== NONE) { + logger.warn('You provided an invalid value for "mode" option.'); + return PRODUCTION; + } return this.args.mode; } if (this.args.prod) { diff --git a/packages/webpack-cli/lib/utils/cli-flags.js b/packages/webpack-cli/lib/utils/cli-flags.js index 063c12f290a..176aa153211 100644 --- a/packages/webpack-cli/lib/utils/cli-flags.js +++ b/packages/webpack-cli/lib/utils/cli-flags.js @@ -272,14 +272,7 @@ module.exports = { { name: 'mode', usage: '--mode ', - type: (value) => { - if (value === 'development' || value === 'production' || value === 'none') { - return value ; - } else { - logger.warn('You provided an invalid value for "mode" option.'); - return 'production' ; - } - }, + type: String, group: ZERO_CONFIG_GROUP, description: 'Defines the mode to pass to webpack', link: 'https://webpack.js.org/concepts/#mode' diff --git a/test/config/basic/basic-config.test.js b/test/config/basic/basic-config.test.js index aeebd213a63..6eba772f6b0 100644 --- a/test/config/basic/basic-config.test.js +++ b/test/config/basic/basic-config.test.js @@ -6,7 +6,7 @@ const { run } = require('../../utils/test-utils'); describe('basic config file', () => { it('is able to understand and parse a very basic configuration file', done => { const { stdout, stderr } = run(__dirname, ['-c', resolve(__dirname, 'webpack.config.js'), '--output', './binary/a.bundle.js']); - expect(stderr).toContain('Duplicate flags found, defaulting to last set value'); + expect(stderr).toBeFalsy(); expect(stdout).not.toBe(undefined); stat(resolve(__dirname, './binary/a.bundle.js'), (err, stats) => { expect(err).toBe(null); diff --git a/test/entry/defaults-index/entry-multi-args.test.js b/test/entry/defaults-index/entry-multi-args.test.js index e8462a4f75a..862d33965d9 100644 --- a/test/entry/defaults-index/entry-multi-args.test.js +++ b/test/entry/defaults-index/entry-multi-args.test.js @@ -19,7 +19,7 @@ describe('single entry flag index present', () => { it('finds default index file, compiles and overrides with flags successfully', done => { const { stderr } = run(__dirname, ['--output', 'bin/main.js']); - expect(stderr).toContain('Duplicate flags found, defaulting to last set value'); + expect(stderr).toBeFalsy(); stat(resolve(__dirname, './bin/main.js'), (err, stats) => { expect(err).toBe(null); diff --git a/test/stats/stats.test.js b/test/stats/stats.test.js index b0b27c278ad..fb69293d7ff 100644 --- a/test/stats/stats.test.js +++ b/test/stats/stats.test.js @@ -44,7 +44,7 @@ describe('stats flag', () => { it('should warn when an unknown flag stats value is passed', () => { const { stderr, stdout } = run(__dirname, ['--stats', 'foo']); expect(stderr).toBeTruthy(); - expect(stderr).toContain('No value recognised for "stats" option'); + expect(stderr).toContain('invalid value for stats'); expect(stdout).toBeTruthy(); }); }); From a2f01e6c81ffe9f41e1e854c4ec89ca880b342f8 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Sat, 21 Mar 2020 12:39:25 +0530 Subject: [PATCH 07/15] chore: remove command-line-args --- packages/webpack-cli/lib/webpack-cli.js | 7 ------- packages/webpack-cli/package.json | 1 - 2 files changed, 8 deletions(-) diff --git a/packages/webpack-cli/lib/webpack-cli.js b/packages/webpack-cli/lib/webpack-cli.js index e439b0c24f8..55ca273fbb4 100644 --- a/packages/webpack-cli/lib/webpack-cli.js +++ b/packages/webpack-cli/lib/webpack-cli.js @@ -81,13 +81,6 @@ class WebpackCLI extends GroupHelper { return options; } - /** - * It exposes "command-line-args" function - */ - commandLineArgs(...args) { - return commandArgs(...args); - } - getCoreFlags() { return core; } diff --git a/packages/webpack-cli/package.json b/packages/webpack-cli/package.json index ed170589729..1431bc18506 100644 --- a/packages/webpack-cli/package.json +++ b/packages/webpack-cli/package.json @@ -27,7 +27,6 @@ "@webpack-cli/package-utils": "^1.0.1-alpha.4", "ansi-escapes": "^4.2.1", "chalk": "^3.0.0", - "command-line-args": "^5.1.1", "command-line-usage": "^6.1.0", "commander": "^5.0.0", "enquirer": "^2.3.4", From 12d65dde4dfc9f1017b47e8be6024db2eeefff82 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Sat, 21 Mar 2020 12:59:22 +0530 Subject: [PATCH 08/15] chore: remove instance of command-line-args --- packages/webpack-cli/lib/bootstrap.js | 5 ++-- packages/webpack-cli/lib/utils/arg-parser.js | 26 +++++++++++--------- packages/webpack-cli/lib/webpack-cli.js | 1 - 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/webpack-cli/lib/bootstrap.js b/packages/webpack-cli/lib/bootstrap.js index 9ce7849c311..8893fd9af35 100644 --- a/packages/webpack-cli/lib/bootstrap.js +++ b/packages/webpack-cli/lib/bootstrap.js @@ -98,9 +98,8 @@ async function runCLI(cli, commandIsUsed) { const newArgKeys = Object.keys(argsMap).filter(arg => !keysToDelete.includes(argsMap[arg].pos)); // eslint-disable-next-line require-atomic-updates process.argv = newArgKeys; - args = cli.commandLineArgs(core, { stopAtFirstUnknown: false, partial: true }); - - await cli.run(args, core); + args = argParser("", core, process.argv).opts; + await cli.run(args.opts(), core); process.stdout.write('\n'); logger.warn('Duplicate flags found, defaulting to last set value'); } else { diff --git a/packages/webpack-cli/lib/utils/arg-parser.js b/packages/webpack-cli/lib/utils/arg-parser.js index 0ccd86f9a26..3053c0a7622 100644 --- a/packages/webpack-cli/lib/utils/arg-parser.js +++ b/packages/webpack-cli/lib/utils/arg-parser.js @@ -7,22 +7,26 @@ const commander = require("commander"); * @param {object[]} options Array of objects with details about flags * @param {string[]} args process.argv or it's subset */ -function argParser(name, options, args, helpFunction, versionFunction) { +function argParser(name = "", options, args, helpFunction, versionFunction) { const parser = new commander.Command(); // Set parser name parser.name(name); - // Use customized version output - parser.on('option:version', () => { - versionFunction(args); - process.exit(0); - }); + // Use customized version output if available + if (versionFunction) { + parser.on('option:version', () => { + versionFunction(args); + process.exit(0); + }); + } - // Use customised help output - parser.on('option:help', () => { - helpFunction(args); - process.exit(0); - }); + // Use customised help output is avaliable + if (helpFunction) { + parser.on('option:help', () => { + helpFunction(args); + process.exit(0); + }); + } // Allow execution if unknown arguments are present parser.allowUnknownOption(true); diff --git a/packages/webpack-cli/lib/webpack-cli.js b/packages/webpack-cli/lib/webpack-cli.js index 55ca273fbb4..be12c089c54 100644 --- a/packages/webpack-cli/lib/webpack-cli.js +++ b/packages/webpack-cli/lib/webpack-cli.js @@ -4,7 +4,6 @@ const GroupHelper = require('./utils/GroupHelper'); const { Compiler } = require('./utils/Compiler'); const { groups, core } = require('./utils/cli-flags'); const webpackMerge = require('webpack-merge'); -const commandArgs = require('command-line-args'); const { toKebabCase } = require('./utils/helpers'); const defaultCommands = { init: 'init', From 9b5854824abf0a2e97fbea9958a3b55a273c6711 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Sat, 21 Mar 2020 13:19:31 +0530 Subject: [PATCH 09/15] chore: add explaination to the change --- packages/webpack-cli/lib/groups/OutputGroup.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/webpack-cli/lib/groups/OutputGroup.js b/packages/webpack-cli/lib/groups/OutputGroup.js index be24b101b1d..97e3ba0d2af 100644 --- a/packages/webpack-cli/lib/groups/OutputGroup.js +++ b/packages/webpack-cli/lib/groups/OutputGroup.js @@ -27,7 +27,10 @@ class OutputGroup extends GroupHelper { const { args } = this; if (args) { const { output } = args; - if (!output) { + // TODO: Remove comment before merge + // We need to show warning when empty output flag is supplied + // which is set to boolean true by commander + if (!output || output === true) { return; } const outputInfo = path.parse(output); From f424fd19ad8d464f3241d02f69d1a17e8e696358 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Sun, 22 Mar 2020 17:51:37 +0530 Subject: [PATCH 10/15] chore: fix --- packages/webpack-cli/lib/bootstrap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack-cli/lib/bootstrap.js b/packages/webpack-cli/lib/bootstrap.js index 8893fd9af35..6495f8c914d 100644 --- a/packages/webpack-cli/lib/bootstrap.js +++ b/packages/webpack-cli/lib/bootstrap.js @@ -98,7 +98,7 @@ async function runCLI(cli, commandIsUsed) { const newArgKeys = Object.keys(argsMap).filter(arg => !keysToDelete.includes(argsMap[arg].pos)); // eslint-disable-next-line require-atomic-updates process.argv = newArgKeys; - args = argParser("", core, process.argv).opts; + args = argParser("", core, process.argv); await cli.run(args.opts(), core); process.stdout.write('\n'); logger.warn('Duplicate flags found, defaulting to last set value'); From b0549b78a2681bdda55eb15aeb718a4b4e2501b1 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Tue, 24 Mar 2020 18:20:34 +0530 Subject: [PATCH 11/15] chore: migrate serve package --- packages/serve/src/index.ts | 21 ++++++++++++++------- packages/webpack-cli/lib/webpack-cli.js | 11 +++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/serve/src/index.ts b/packages/serve/src/index.ts index f9d6c6eef00..49f2887761d 100644 --- a/packages/serve/src/index.ts +++ b/packages/serve/src/index.ts @@ -19,14 +19,21 @@ export default function serve(...args): void { // we need to parse the dev server args first. Otherwise, the webpack parsing could snatch // one of the dev server's options and set it to this 'entry' option. // see: https://github.com/75lb/command-line-args/blob/master/doc/option-definition.md#optiondefaultoption--boolean - const devServerArgs = cli.commandLineArgs(devServer, { argv: args, partial: true }); - const webpackArgs = cli.commandLineArgs(core, { argv: devServerArgs._unknown || [], stopAtFirstUnknown: false }); - const finalArgs = argsToCamelCase(devServerArgs._all || {}); + const devServerArgs = cli.argParser("", devServer, args); + const webpackArgs = cli.argParser("", core, devServerArgs.args); + const finalArgs = argsToCamelCase(devServerArgs.opts() || {}); // pass along the 'hot' argument to the dev server if it exists - if (webpackArgs && webpackArgs._all && typeof webpackArgs._all.hot !== 'undefined') { - finalArgs['hot'] = webpackArgs._all.hot; - } - cli.getCompiler(webpackArgs, core).then((compiler): void => { + if (webpackArgs && webpackArgs.opts() && typeof webpackArgs.opts().hot !== 'undefined') { + finalArgs['hot'] = webpackArgs.opts().hot; + } + + Object.keys(finalArgs).forEach(arg => { + if (finalArgs[arg] === undefined) { + delete finalArgs[arg]; + } + }); + + cli.getCompiler(webpackArgs.opts(), core).then((compiler): void => { startDevServer(compiler, finalArgs); }); } diff --git a/packages/webpack-cli/lib/webpack-cli.js b/packages/webpack-cli/lib/webpack-cli.js index be12c089c54..fcf0adafd09 100644 --- a/packages/webpack-cli/lib/webpack-cli.js +++ b/packages/webpack-cli/lib/webpack-cli.js @@ -5,6 +5,8 @@ const { Compiler } = require('./utils/Compiler'); const { groups, core } = require('./utils/cli-flags'); const webpackMerge = require('webpack-merge'); const { toKebabCase } = require('./utils/helpers'); +const argParser = require('./utils/arg-parser'); + const defaultCommands = { init: 'init', loader: 'generate-loader', @@ -80,6 +82,15 @@ class WebpackCLI extends GroupHelper { return options; } + /** + * Expose commander argParser + * @param {...any} args args for argParser + */ + argParser(...args) { + return argParser(...args); + } + + getCoreFlags() { return core; } From feb620040cd2d98cae002c054f25d584a6961fbf Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Tue, 24 Mar 2020 18:48:22 +0530 Subject: [PATCH 12/15] chore: handle error --- packages/serve/src/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/serve/src/index.ts b/packages/serve/src/index.ts index 49f2887761d..5139be74541 100644 --- a/packages/serve/src/index.ts +++ b/packages/serve/src/index.ts @@ -33,6 +33,10 @@ export default function serve(...args): void { } }); + if (webpackArgs.args.length > 0) { + process.stderr.write(`Unknown argument: ${webpackArgs.args} flag`); + } + cli.getCompiler(webpackArgs.opts(), core).then((compiler): void => { startDevServer(compiler, finalArgs); }); From 6194d3a2dd2a3e64cfeb008244ec83de777077f6 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Thu, 26 Mar 2020 12:30:31 +0530 Subject: [PATCH 13/15] chore: reactor argparser --- packages/serve/src/index.ts | 19 +++++++++++-------- packages/webpack-cli/lib/bootstrap.js | 2 +- packages/webpack-cli/lib/utils/arg-parser.js | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/serve/src/index.ts b/packages/serve/src/index.ts index 5139be74541..f9703edc1c7 100644 --- a/packages/serve/src/index.ts +++ b/packages/serve/src/index.ts @@ -1,5 +1,5 @@ import { devServer } from "webpack-dev-server/bin/cli-flags"; -import WebpackCLI from "webpack-cli"; +import WebpackCLI from "../../webpack-cli"; import startDevServer from "./startDevServer"; import argsToCamelCase from "./args-to-camel-case"; @@ -13,18 +13,20 @@ import argsToCamelCase from "./args-to-camel-case"; export default function serve(...args): void { const cli = new WebpackCLI(); const core = cli.getCoreFlags(); - // partial parsing usage: https://github.com/75lb/command-line-args/wiki/Partial-parsing + + // partial parsing usage: https://github.com/75lb/command-line-args/wiki/Partial-parsing // since the webpack flags have the 'entry' option set as it's default option, // we need to parse the dev server args first. Otherwise, the webpack parsing could snatch // one of the dev server's options and set it to this 'entry' option. // see: https://github.com/75lb/command-line-args/blob/master/doc/option-definition.md#optiondefaultoption--boolean - const devServerArgs = cli.argParser("", devServer, args); - const webpackArgs = cli.argParser("", core, devServerArgs.args); - const finalArgs = argsToCamelCase(devServerArgs.opts() || {}); + const devServerArgs = cli.argParser(devServer, args); + const webpackArgs = cli.argParser(core, args, process.title, cli.runHelp, cli.runVersion); + + const finalArgs = argsToCamelCase(devServerArgs.opts() || {}); // pass along the 'hot' argument to the dev server if it exists - if (webpackArgs && webpackArgs.opts() && typeof webpackArgs.opts().hot !== 'undefined') { - finalArgs['hot'] = webpackArgs.opts().hot; + if (webpackArgs && webpackArgs.opts() && webpackArgs.opts().hot !== undefined) { + finalArgs['hot'] = webpackArgs.opts().hot; } Object.keys(finalArgs).forEach(arg => { @@ -34,7 +36,8 @@ export default function serve(...args): void { }); if (webpackArgs.args.length > 0) { - process.stderr.write(`Unknown argument: ${webpackArgs.args} flag`); + process.stderr.write(`Unknown argument: ${webpackArgs.args}`); + return; } cli.getCompiler(webpackArgs.opts(), core).then((compiler): void => { diff --git a/packages/webpack-cli/lib/bootstrap.js b/packages/webpack-cli/lib/bootstrap.js index 6495f8c914d..116951f2b3c 100644 --- a/packages/webpack-cli/lib/bootstrap.js +++ b/packages/webpack-cli/lib/bootstrap.js @@ -43,7 +43,7 @@ const resolveNegatedArgs = args => { }; async function runCLI(cli, commandIsUsed) { - const parsedArgs = argParser('webpack', core, process.argv, cli.runHelp, cli.runVersion); + const parsedArgs = argParser(core, process.argv, process.title, cli.runHelp, cli.runVersion); if (parsedArgs.args.includes('help')) { cli.runHelp(process.argv); diff --git a/packages/webpack-cli/lib/utils/arg-parser.js b/packages/webpack-cli/lib/utils/arg-parser.js index 3053c0a7622..4fa97f4133a 100644 --- a/packages/webpack-cli/lib/utils/arg-parser.js +++ b/packages/webpack-cli/lib/utils/arg-parser.js @@ -7,7 +7,7 @@ const commander = require("commander"); * @param {object[]} options Array of objects with details about flags * @param {string[]} args process.argv or it's subset */ -function argParser(name = "", options, args, helpFunction, versionFunction) { +function argParser(options, args, name = "", helpFunction = undefined, versionFunction = undefined) { const parser = new commander.Command(); // Set parser name parser.name(name); From 296f46b7e7524c3772496b1061130ac4319a6104 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Thu, 26 Mar 2020 14:56:16 +0530 Subject: [PATCH 14/15] chore: get serve args from process.argv --- packages/serve/src/index.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/serve/src/index.ts b/packages/serve/src/index.ts index f9703edc1c7..f9334f19bf4 100644 --- a/packages/serve/src/index.ts +++ b/packages/serve/src/index.ts @@ -10,21 +10,17 @@ import argsToCamelCase from "./args-to-camel-case"; * @param {String[]} args - args processed from the CLI * @returns {Function} invokes the devServer API */ -export default function serve(...args): void { +export default function serve(): void { const cli = new WebpackCLI(); const core = cli.getCoreFlags(); - // partial parsing usage: https://github.com/75lb/command-line-args/wiki/Partial-parsing + const filteredArgs = process.argv.filter(arg => (arg != "serve")); + const devServerArgs = cli.argParser(devServer, filteredArgs); + const webpackArgs = cli.argParser(core, filteredArgs, process.title, cli.runHelp, cli.runVersion); + const finalArgs = argsToCamelCase(devServerArgs.opts() || {}); - // since the webpack flags have the 'entry' option set as it's default option, - // we need to parse the dev server args first. Otherwise, the webpack parsing could snatch - // one of the dev server's options and set it to this 'entry' option. - // see: https://github.com/75lb/command-line-args/blob/master/doc/option-definition.md#optiondefaultoption--boolean - const devServerArgs = cli.argParser(devServer, args); - const webpackArgs = cli.argParser(core, args, process.title, cli.runHelp, cli.runVersion); - const finalArgs = argsToCamelCase(devServerArgs.opts() || {}); - // pass along the 'hot' argument to the dev server if it exists + // pass along the 'hot' argument to the dev server if it exists if (webpackArgs && webpackArgs.opts() && webpackArgs.opts().hot !== undefined) { finalArgs['hot'] = webpackArgs.opts().hot; } From 65608d360dc9ec776546d1b8f7517df068cf31f8 Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Thu, 26 Mar 2020 14:59:50 +0530 Subject: [PATCH 15/15] chore: sync message with test --- packages/serve/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/serve/src/index.ts b/packages/serve/src/index.ts index f9334f19bf4..5242d35b985 100644 --- a/packages/serve/src/index.ts +++ b/packages/serve/src/index.ts @@ -32,7 +32,7 @@ export default function serve(): void { }); if (webpackArgs.args.length > 0) { - process.stderr.write(`Unknown argument: ${webpackArgs.args}`); + process.stderr.write(`Unknown option: ${webpackArgs.args}`); return; }