diff --git a/INIT.md b/INIT.md index e32506e556e..6b774d07df4 100644 --- a/INIT.md +++ b/INIT.md @@ -2,11 +2,21 @@ `webpack-cli init` is used to initialize `webpack` projects quickly by scaffolding configuration and creating a runnable project with all the dependencies based on the user preferences. +## Table of Contents + +- [Initial Setup](#initial-setup) + - [Local Setup](#local-setup) + - [Global Setup](#global-setup) +- [Usage](#usage) + - [Running Globally](#running-globally) + - [Running Locally](#running-locally) + - [Description of questions asked by generator](#description-of-questions-asked-by-generator) + ## Initial Setup -### a. Local setup +### a. Local Setup -These are the steps necessary to setup `webpack-cli init` locally: +These are the steps necessary to set up `webpack-cli init` locally: 1. Create `package.json` through npm @@ -28,7 +38,7 @@ These are the steps necessary to setup `webpack-cli init` locally: ### b. Global Setup -These are the steps necessary to setup `webpack-cli init` globally: +These are the steps necessary to set up `webpack-cli init` globally: 1. Install `webpack` and `webpack-cli` globally @@ -44,19 +54,19 @@ These are the steps necessary to setup `webpack-cli init` globally: ## Usage -### a. Running locally +### a. Running Locally ```shell npx webpack-cli init ``` -### b. Running globally +### b. Running Globally ```shell webpack-cli init ``` -### Description of questions asked by generator +### Description of questions asked by the generator 1. `Will your application have multiple bundles? (y/N)` diff --git a/MIGRATE.md b/MIGRATE.md index c659d4caa28..150418dfc62 100644 --- a/MIGRATE.md +++ b/MIGRATE.md @@ -7,6 +7,17 @@ The `webpack-cli migrate` feature eases the transition from: `webpack-cli migrate` also allows users to switch to the new version of webpack without having to do it extensively. +## Table of Contents + +- [Installation](#installation) + - [Local Setup](#local-setup) + - [Global Setup](#global-setup) +- [Usage](#usage) + - [Local Setup](#local-setup) + - [Global Setup](#global-setup) + - [Usage Example](#usage-example) +- [Changes reflected after migration](#changes-reflected-after-migration) + ## Installation > Requires installation of `webpack` and `webpack-cli` diff --git a/packages/webpack-cli/README.md b/packages/webpack-cli/README.md index cc2efc2e11e..f0c22ff18ab 100644 --- a/packages/webpack-cli/README.md +++ b/packages/webpack-cli/README.md @@ -56,6 +56,7 @@ Options -v, --version Get current version --node-args string[] NodeJS flags --stats string It instructs webpack on how to treat the stats + --no-stats Disables stats output --verbose It tells webpack to output all the information ``` diff --git a/packages/webpack-cli/lib/bootstrap.js b/packages/webpack-cli/lib/bootstrap.js index a088a32e671..265f19278aa 100644 --- a/packages/webpack-cli/lib/bootstrap.js +++ b/packages/webpack-cli/lib/bootstrap.js @@ -7,14 +7,6 @@ require('./utils/process-log'); process.title = 'webpack-cli'; -// const isFlagPresent = (args, flag) => args.find((arg) => [flag, `--${flag}`].includes(arg)); -const isArgCommandName = (arg, cmd) => arg === cmd.name || arg === cmd.alias; -const removeCmdFromArgs = (args, cmd) => args.filter((arg) => !isArgCommandName(arg, cmd)); -const normalizeFlags = (args, cmd) => { - const slicedArgs = args.slice(2); - return removeCmdFromArgs(slicedArgs, cmd); -}; - const isCommandUsed = (commands) => commands.find((cmd) => { return process.argv.includes(cmd.name) || process.argv.includes(cmd.alias); @@ -25,7 +17,7 @@ async function runCLI(cli, commandIsUsed) { const runVersion = () => { cli.runVersion(process.argv, commandIsUsed); }; - const parsedArgs = argParser(core, process.argv, false, process.title, cli.runHelp, runVersion); + const parsedArgs = argParser(core, process.argv, false, process.title, cli.runHelp, runVersion, commands); if (parsedArgs.unknownArgs.includes('help')) { cli.runHelp(process.argv); @@ -38,74 +30,72 @@ async function runCLI(cli, commandIsUsed) { } if (commandIsUsed) { - commandIsUsed.defaultOption = true; - args = normalizeFlags(process.argv, commandIsUsed); - return await cli.runCommand(commandIsUsed, ...args); - } else { - try { - // handle the default webpack entry CLI argument, where instead - // of doing 'webpack-cli --entry ./index.js' you can simply do - // 'webpack-cli ./index.js' - // if the unknown arg starts with a '-', it will be considered - // an unknown flag rather than an entry - let entry; - if (parsedArgs.unknownArgs.length > 0 && !parsedArgs.unknownArgs[0].startsWith('-')) { - if (parsedArgs.unknownArgs.length === 1) { - entry = parsedArgs.unknownArgs[0]; - } else { - entry = []; - parsedArgs.unknownArgs.forEach((unknown) => { - if (!unknown.startsWith('-')) { - entry.push(unknown); - } - }); - } - } else if (parsedArgs.unknownArgs.length > 0) { + return; + } + + try { + // handle the default webpack entry CLI argument, where instead + // of doing 'webpack-cli --entry ./index.js' you can simply do + // 'webpack-cli ./index.js' + // if the unknown arg starts with a '-', it will be considered + // an unknown flag rather than an entry + let entry; + if (parsedArgs.unknownArgs.length > 0 && !parsedArgs.unknownArgs[0].startsWith('-')) { + if (parsedArgs.unknownArgs.length === 1) { + entry = parsedArgs.unknownArgs[0]; + } else { + entry = []; parsedArgs.unknownArgs.forEach((unknown) => { - logger.warn('Unknown argument:', unknown); - }); - cliExecuter(); - return; - } - const parsedArgsOpts = parsedArgs.opts; - if (entry) { - parsedArgsOpts.entry = entry; - } - const result = await cli.run(parsedArgsOpts, core); - if (!result) { - return; - } - } catch (err) { - if (err.name === 'UNKNOWN_VALUE') { - logger.error(`Parse Error (unknown argument): ${err.value}`); - return; - } else if (err.name === 'ALREADY_SET') { - const argsMap = {}; - const keysToDelete = []; - process.argv.forEach((arg, idx) => { - const oldMapValue = argsMap[arg]; - argsMap[arg] = { - value: process.argv[idx], - pos: idx, - }; - // Swap idx of overridden value - if (oldMapValue) { - argsMap[arg].pos = oldMapValue.pos; - keysToDelete.push(idx + 1); + if (!unknown.startsWith('-')) { + entry.push(unknown); } }); - // Filter out the value for the overridden key - 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); - await cli.run(args.opts, core); - process.stdout.write('\n'); - logger.warn('Duplicate flags found, defaulting to last set value'); - } else { - logger.error(err); - return; } + } else if (parsedArgs.unknownArgs.length > 0) { + parsedArgs.unknownArgs.forEach((unknown) => { + logger.warn('Unknown argument:', unknown); + }); + cliExecuter(); + return; + } + const parsedArgsOpts = parsedArgs.opts; + if (entry) { + parsedArgsOpts.entry = entry; + } + const result = await cli.run(parsedArgsOpts, core); + if (!result) { + return; + } + } catch (err) { + if (err.name === 'UNKNOWN_VALUE') { + logger.error(`Parse Error (unknown argument): ${err.value}`); + return; + } else if (err.name === 'ALREADY_SET') { + const argsMap = {}; + const keysToDelete = []; + process.argv.forEach((arg, idx) => { + const oldMapValue = argsMap[arg]; + argsMap[arg] = { + value: process.argv[idx], + pos: idx, + }; + // Swap idx of overridden value + if (oldMapValue) { + argsMap[arg].pos = oldMapValue.pos; + keysToDelete.push(idx + 1); + } + }); + // Filter out the value for the overridden key + 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); + await cli.run(args.opts, core); + process.stdout.write('\n'); + logger.warn('Duplicate flags found, defaulting to last set value'); + } else { + logger.error(err); + return; } } } diff --git a/packages/webpack-cli/lib/groups/ConfigGroup.js b/packages/webpack-cli/lib/groups/ConfigGroup.js index bf75f70b74f..dbeb549fcb7 100644 --- a/packages/webpack-cli/lib/groups/ConfigGroup.js +++ b/packages/webpack-cli/lib/groups/ConfigGroup.js @@ -4,14 +4,28 @@ const { extensions } = require('interpret'); const GroupHelper = require('../utils/GroupHelper'); const rechoir = require('rechoir'); +// Order defines the priority, in increasing order +// example - config file lookup will be in order of .webpack/webpack.config.development.js -> webpack.config.development.js -> webpack.config.js const DEFAULT_CONFIG_LOC = [ + 'webpack.config', + 'webpack.config.dev', + 'webpack.config.development', + 'webpack.config.prod', + 'webpack.config.production', '.webpack/webpack.config', + '.webpack/webpack.config.none', '.webpack/webpack.config.dev', + '.webpack/webpack.config.development', '.webpack/webpack.config.prod', + '.webpack/webpack.config.production', '.webpack/webpackfile', - 'webpack.config', ]; +const modeAlias = { + production: 'prod', + development: 'dev', +}; + const fileTypes = { '.babel.js': ['@babel/register', 'babel-register', 'babel-core/register', 'babel/register'], '.babel.ts': ['@babel/register'], @@ -136,10 +150,9 @@ class ConfigGroup extends GroupHelper { const configFiles = tmpConfigFiles.map(this.requireConfig.bind(this)); if (configFiles.length) { - const defaultConfig = configFiles.find((p) => p.path.includes(mode)); + const defaultConfig = configFiles.find((p) => p.path.includes(mode) || p.path.includes(modeAlias[mode])); if (defaultConfig) { - const envConfig = defaultConfig.map((c) => c.content); - this.opts = this.finalize(envConfig); + this.opts = this.finalize(defaultConfig); return; } const foundConfig = configFiles.pop(); diff --git a/packages/webpack-cli/lib/groups/StatsGroup.js b/packages/webpack-cli/lib/groups/StatsGroup.js index efd7536afa5..8ce228d909e 100644 --- a/packages/webpack-cli/lib/groups/StatsGroup.js +++ b/packages/webpack-cli/lib/groups/StatsGroup.js @@ -5,7 +5,7 @@ const logger = require('../utils/logger'); */ class StatsGroup extends GroupHelper { static validOptions() { - return ['none', 'errors-only', 'minimal', 'normal', 'detailed', 'verbose', 'errors-warnings', true]; + return ['none', 'errors-only', 'minimal', 'normal', 'detailed', 'verbose', 'errors-warnings', true, false]; } constructor(options) { diff --git a/packages/webpack-cli/lib/utils/arg-parser.js b/packages/webpack-cli/lib/utils/arg-parser.js index 493793d959a..db76c2f7ef5 100644 --- a/packages/webpack-cli/lib/utils/arg-parser.js +++ b/packages/webpack-cli/lib/utils/arg-parser.js @@ -1,6 +1,15 @@ const commander = require('commander'); const logger = require('./logger'); +const defaultCommands = { + init: 'init', + loader: 'generate-loader', + plugin: 'generate-plugin', + info: 'info', + migrate: 'migrate', + serve: 'serve', +}; + /** * Creates Argument parser corresponding to the supplied options * parse the args and return the result @@ -10,11 +19,30 @@ const logger = require('./logger'); * @param {boolean} argsOnly false if all of process.argv has been provided, true if * args is only a subset of process.argv that removes the first couple elements */ -function argParser(options, args, argsOnly = false, name = '', helpFunction = undefined, versionFunction = undefined) { +function argParser(options, args, argsOnly = false, name = '', helpFunction = undefined, versionFunction = undefined, commands) { const parser = new commander.Command(); // Set parser name parser.name(name); + if (commands) { + commands.reduce((parserInstance, cmd) => { + parser + .command(cmd.name) + .alias(cmd.alias) + .description(cmd.description) + .usage(cmd.usage) + .allowUnknownOption(true) + .action(async () => { + const cliArgs = args.slice(args.indexOf(cmd.name) + 1 || args.indexOf(cmd.alias) + 1); + return await require('../commands/ExternalCommand').run(defaultCommands[cmd.name], ...cliArgs); + }); + return parser; + }, parser); + + // Prevent default behavior + parser.on('command:*', () => {}); + } + // Use customized version output if available if (versionFunction) { parser.on('option:version', () => { @@ -40,10 +68,11 @@ function argParser(options, args, argsOnly = false, name = '', helpFunction = un let flagsWithType = option.type !== Boolean ? flags + ' ' : flags; if (option.type === Boolean || option.type === String) { if (!option.multiple) { - parserInstance.option(flagsWithType, option.description, option.defaultValue); + // Prevent default behavior for standalone options + parserInstance.option(flagsWithType, option.description, option.defaultValue).action(() => {}); } else { const multiArg = (value, previous = []) => previous.concat([value]); - parserInstance.option(flagsWithType, option.description, multiArg, option.defaultValue); + parserInstance.option(flagsWithType, option.description, multiArg, option.defaultValue).action(() => {}); } } else if (option.type === Number) { parserInstance.option(flagsWithType, option.description, Number, option.defaultValue); @@ -51,9 +80,9 @@ function argParser(options, args, argsOnly = false, name = '', helpFunction = un // in this case the type is a parsing function if (option.type.length > 1) { flagsWithType = flags + ' [value]'; - parserInstance.option(flagsWithType, option.description, option.type[0], option.defaultValue); + parserInstance.option(flagsWithType, option.description, option.type[0], option.defaultValue).action(() => {}); } else { - parserInstance.option(flagsWithType, option.description, option.type, option.defaultValue); + parserInstance.option(flagsWithType, option.description, option.type, option.defaultValue).action(() => {}); } } diff --git a/packages/webpack-cli/lib/utils/cli-flags.js b/packages/webpack-cli/lib/utils/cli-flags.js index 27906e6f0ef..a19529c5963 100644 --- a/packages/webpack-cli/lib/utils/cli-flags.js +++ b/packages/webpack-cli/lib/utils/cli-flags.js @@ -245,6 +245,14 @@ module.exports = { description: 'It instructs webpack on how to treat the stats e.g. verbose', link: 'https://webpack.js.org/configuration/stats/#stats', }, + { + name: 'no-stats', + usage: '--no-stats', + type: Boolean, + group: DISPLAY_GROUP, + description: 'Disables stats output', + link: 'https://webpack.js.org/configuration/stats/#stats', + }, { name: 'verbose', usage: '--verbose', diff --git a/packages/webpack-cli/lib/webpack-cli.js b/packages/webpack-cli/lib/webpack-cli.js index ae8e18683bc..01ba4e762c4 100644 --- a/packages/webpack-cli/lib/webpack-cli.js +++ b/packages/webpack-cli/lib/webpack-cli.js @@ -5,15 +5,6 @@ const webpackMerge = require('webpack-merge'); const { toKebabCase } = require('./utils/helpers'); const argParser = require('./utils/arg-parser'); -const defaultCommands = { - init: 'init', - loader: 'generate-loader', - plugin: 'generate-plugin', - info: 'info', - migrate: 'migrate', - serve: 'serve', -}; - class WebpackCLI extends GroupHelper { constructor() { super(); @@ -31,7 +22,7 @@ class WebpackCLI extends GroupHelper { `./src/${this.defaultEntry}.js`, `src/${this.defaultEntry}.js`, ]; - this.compilerConfiguration = undefined; + this.compilerConfiguration = {}; this.outputConfiguration = {}; } setMappedGroups(args, inlineOptions) { @@ -71,6 +62,11 @@ class WebpackCLI extends GroupHelper { */ resolveGroups() { let mode; + // determine the passed mode for ConfigGroup + if (this.groupMap.has(groups.ZERO_CONFIG_GROUP)) { + const modePresent = this.groupMap.get(groups.ZERO_CONFIG_GROUP).find((t) => !!t.mode); + if (modePresent) mode = modePresent.mode; + } for (const [key, value] of this.groupMap.entries()) { switch (key) { case groups.ZERO_CONFIG_GROUP: { @@ -256,11 +252,6 @@ class WebpackCLI extends GroupHelper { return webpack; } - async runCommand(command, ...args) { - // TODO: rename and depreciate init - return await require('./commands/ExternalCommand').run(defaultCommands[command.name], ...args); - } - runHelp(args) { const HelpGroup = require('./groups/HelpGroup'); const { commands, allNames, hasUnknownArgs } = require('./utils/unknown-args'); diff --git a/test/config/multiple/.webpack/webpack.config.dev.js b/test/config/multiple/all/.webpack/webpack.config.dev.js similarity index 100% rename from test/config/multiple/.webpack/webpack.config.dev.js rename to test/config/multiple/all/.webpack/webpack.config.dev.js diff --git a/test/config/multiple/all/.webpack/webpack.config.none.js b/test/config/multiple/all/.webpack/webpack.config.none.js new file mode 100644 index 00000000000..be0482a8df2 --- /dev/null +++ b/test/config/multiple/all/.webpack/webpack.config.none.js @@ -0,0 +1,9 @@ +const { resolve } = require('path'); + +module.exports = { + entry: './index.js', + output: { + path: resolve(__dirname, '../binary'), + filename: 'none.bundle.js', + }, +}; diff --git a/test/config/multiple/.webpack/webpack.config.prod.js b/test/config/multiple/all/.webpack/webpack.config.prod.js similarity index 100% rename from test/config/multiple/.webpack/webpack.config.prod.js rename to test/config/multiple/all/.webpack/webpack.config.prod.js diff --git a/test/config/multiple/index.js b/test/config/multiple/all/index.js similarity index 100% rename from test/config/multiple/index.js rename to test/config/multiple/all/index.js diff --git a/test/config/multiple/multiple-config.test.js b/test/config/multiple/all/multiple-config.test.js similarity index 64% rename from test/config/multiple/multiple-config.test.js rename to test/config/multiple/all/multiple-config.test.js index 4983752e7ca..cf653dd67a0 100644 --- a/test/config/multiple/multiple-config.test.js +++ b/test/config/multiple/all/multiple-config.test.js @@ -1,9 +1,15 @@ 'use strict'; const { stat } = require('fs'); -const { resolve } = require('path'); -const { run } = require('../../utils/test-utils'); +const { resolve, join } = require('path'); +const { run } = require('../../../utils/test-utils'); +const rimraf = require('rimraf'); + +const outputPath = join(__dirname, 'binary'); describe('multiple config files', () => { + afterEach(() => rimraf.sync(outputPath)); + beforeAll(() => rimraf.sync(outputPath)); + it('Uses prod config from dot folder if present', (done) => { const { stdout, stderr } = run(__dirname, [], false); expect(stderr).toBeFalsy(); diff --git a/test/config/multiple/multiple-location/.webpack/webpack.config.development.js b/test/config/multiple/multiple-location/.webpack/webpack.config.development.js new file mode 100644 index 00000000000..251a60f7352 --- /dev/null +++ b/test/config/multiple/multiple-location/.webpack/webpack.config.development.js @@ -0,0 +1,9 @@ +const { resolve } = require('path'); + +module.exports = { + entry: './index.js', + output: { + path: resolve(__dirname, '../binary'), + filename: 'dev.folder.js', + }, +}; diff --git a/test/config/multiple/multiple-location/index.js b/test/config/multiple/multiple-location/index.js new file mode 100644 index 00000000000..73459aced0d --- /dev/null +++ b/test/config/multiple/multiple-location/index.js @@ -0,0 +1 @@ +console.log("Tanjiro") diff --git a/test/config/multiple/multiple-location/multiple-location-config.test.js b/test/config/multiple/multiple-location/multiple-location-config.test.js new file mode 100644 index 00000000000..e1d71844fec --- /dev/null +++ b/test/config/multiple/multiple-location/multiple-location-config.test.js @@ -0,0 +1,23 @@ +'use strict'; +const { stat } = require('fs'); +const { resolve, join } = require('path'); +const { run } = require('../../../utils/test-utils'); +const rimraf = require('rimraf'); + +const outputPath = join(__dirname, 'binary'); + +describe('multiple dev config files with webpack.config.js', () => { + afterEach(() => rimraf.sync(outputPath)); + beforeAll(() => rimraf.sync(outputPath)); + + it('Uses webpack.config.development.js', (done) => { + const { stdout, stderr } = run(__dirname, [], false); + expect(stderr).toBeFalsy(); + expect(stdout).not.toBe(undefined); + stat(resolve(__dirname, './binary/dev.folder.js'), (err, stats) => { + expect(err).toBe(null); + expect(stats.isFile()).toBe(true); + done(); + }); + }); +}); diff --git a/test/config/multiple/multiple-location/webpack.config.development.js b/test/config/multiple/multiple-location/webpack.config.development.js new file mode 100644 index 00000000000..3ce4e5a7356 --- /dev/null +++ b/test/config/multiple/multiple-location/webpack.config.development.js @@ -0,0 +1,9 @@ +const { resolve } = require('path'); + +module.exports = { + entry: './index.js', + output: { + path: resolve(__dirname, './binary'), + filename: 'development.bundle.js', + }, +}; diff --git a/test/config/multiple/multiple-location/webpack.config.js b/test/config/multiple/multiple-location/webpack.config.js new file mode 100644 index 00000000000..be128f00ca0 --- /dev/null +++ b/test/config/multiple/multiple-location/webpack.config.js @@ -0,0 +1,9 @@ +const { resolve } = require('path'); + +module.exports = { + entry: './index.js', + output: { + path: resolve(__dirname, './binary'), + filename: 'root.bundle.js', + }, +}; diff --git a/test/config/multiple/none and dev/.webpack/webpack.config.dev.js b/test/config/multiple/none and dev/.webpack/webpack.config.dev.js new file mode 100644 index 00000000000..ba00a518a7d --- /dev/null +++ b/test/config/multiple/none and dev/.webpack/webpack.config.dev.js @@ -0,0 +1,9 @@ +const { resolve } = require('path'); + +module.exports = { + entry: './index.js', + output: { + path: resolve(__dirname, '../binary'), + filename: 'dev.bundle.js', + }, +}; diff --git a/test/config/multiple/none and dev/.webpack/webpack.config.none.js b/test/config/multiple/none and dev/.webpack/webpack.config.none.js new file mode 100644 index 00000000000..be0482a8df2 --- /dev/null +++ b/test/config/multiple/none and dev/.webpack/webpack.config.none.js @@ -0,0 +1,9 @@ +const { resolve } = require('path'); + +module.exports = { + entry: './index.js', + output: { + path: resolve(__dirname, '../binary'), + filename: 'none.bundle.js', + }, +}; diff --git a/test/config/multiple/none and dev/dev-none-config.test.js b/test/config/multiple/none and dev/dev-none-config.test.js new file mode 100644 index 00000000000..563460be5a4 --- /dev/null +++ b/test/config/multiple/none and dev/dev-none-config.test.js @@ -0,0 +1,23 @@ +'use strict'; +const { stat } = require('fs'); +const { resolve, join } = require('path'); +const { run } = require('../../../utils/test-utils'); +const rimraf = require('rimraf'); + +const outputPath = join(__dirname, 'binary'); + +describe('multiple config files', () => { + afterEach(() => rimraf.sync(outputPath)); + beforeAll(() => rimraf.sync(outputPath)); + + it('Uses dev config when both dev and none are present', (done) => { + const { stdout, stderr } = run(__dirname, [], false); + expect(stderr).toBeFalsy(); + expect(stdout).not.toBe(undefined); + stat(resolve(__dirname, './binary/dev.bundle.js'), (err, stats) => { + expect(err).toBe(null); + expect(stats.isFile()).toBe(true); + done(); + }); + }); +}); diff --git a/test/config/multiple/none and dev/index.js b/test/config/multiple/none and dev/index.js new file mode 100644 index 00000000000..0483dbadb45 --- /dev/null +++ b/test/config/multiple/none and dev/index.js @@ -0,0 +1 @@ +console.log("Kageyama") diff --git a/test/config/multiple/with-mode/index.js b/test/config/multiple/with-mode/index.js new file mode 100644 index 00000000000..458b8dc3316 --- /dev/null +++ b/test/config/multiple/with-mode/index.js @@ -0,0 +1 @@ +console.log("Iwaizumi") diff --git a/test/config/multiple/with-mode/multiple-config.test.js b/test/config/multiple/with-mode/multiple-config.test.js new file mode 100644 index 00000000000..dd4b986fef0 --- /dev/null +++ b/test/config/multiple/with-mode/multiple-config.test.js @@ -0,0 +1,23 @@ +'use strict'; +const { stat } = require('fs'); +const { resolve, join } = require('path'); +const { run } = require('../../../utils/test-utils'); +const rimraf = require('rimraf'); + +const outputPath = join(__dirname, 'binary'); + +describe('multiple config files', () => { + afterEach(() => rimraf.sync(outputPath)); + beforeAll(() => rimraf.sync(outputPath)); + + it('Uses dev config when development mode is supplied', (done) => { + const { stdout, stderr } = run(__dirname, ['--mode', 'development'], false); + expect(stderr).toBeFalsy(); + expect(stdout).not.toBe(undefined); + stat(resolve(__dirname, './binary/dev.bundle.js'), (err, stats) => { + expect(err).toBe(null); + expect(stats.isFile()).toBe(true); + done(); + }); + }); +}); diff --git a/test/config/multiple/with-mode/webpack.config.development.js b/test/config/multiple/with-mode/webpack.config.development.js new file mode 100644 index 00000000000..0e8c35c932f --- /dev/null +++ b/test/config/multiple/with-mode/webpack.config.development.js @@ -0,0 +1,9 @@ +const { resolve } = require('path'); + +module.exports = { + entry: './index.js', + output: { + path: resolve(__dirname, './binary'), + filename: 'dev.bundle.js', + }, +}; diff --git a/test/config/multiple/with-mode/webpack.config.none.js b/test/config/multiple/with-mode/webpack.config.none.js new file mode 100644 index 00000000000..ade0d9bb8e8 --- /dev/null +++ b/test/config/multiple/with-mode/webpack.config.none.js @@ -0,0 +1,9 @@ +const { resolve } = require('path'); + +module.exports = { + entry: './index.js', + output: { + path: resolve(__dirname, './binary'), + filename: 'none.bundle.js', + }, +}; diff --git a/test/config/multiple/with-mode/webpack.config.production.js b/test/config/multiple/with-mode/webpack.config.production.js new file mode 100644 index 00000000000..462320690d9 --- /dev/null +++ b/test/config/multiple/with-mode/webpack.config.production.js @@ -0,0 +1,9 @@ +const { resolve } = require('path'); + +module.exports = { + entry: './index.js', + output: { + path: resolve(__dirname, './binary'), + filename: 'prod.bundle.js', + }, +}; diff --git a/test/no-stats/with-config/main.js b/test/no-stats/with-config/main.js new file mode 100644 index 00000000000..1f23f48394d --- /dev/null +++ b/test/no-stats/with-config/main.js @@ -0,0 +1,4 @@ +require('url'); +require('path'); + +console.log('--no-stats with config test'); diff --git a/test/no-stats/with-config/no-stats-with-config.test.js b/test/no-stats/with-config/no-stats-with-config.test.js new file mode 100644 index 00000000000..99dc73dd87d --- /dev/null +++ b/test/no-stats/with-config/no-stats-with-config.test.js @@ -0,0 +1,29 @@ +'use strict'; +// eslint-disable-next-line node/no-unpublished-require +const { run } = require('../../utils/test-utils'); +// eslint-disable-next-line node/no-extraneous-require +const { version } = require('webpack'); + +describe('stats flag', () => { + it(`should use stats 'detailed' as defined in webpack config`, () => { + const { stderr, stdout } = run(__dirname, []); + + expect(stderr).toBeFalsy(); + if (version.startsWith('5')) { + expect(stdout).toContain(`stats: { preset: 'detailed' }`); + } else { + expect(stdout).toContain(`stats: 'detailed'`); + } + }); + + it(`should use --no-stats and override value in config`, () => { + const { stderr, stdout } = run(__dirname, ['--no-stats']); + + expect(stderr).toBeFalsy(); + if (version.startsWith('5')) { + expect(stdout).toContain(`stats: { preset: 'none' }`); + } else { + expect(stdout).toContain(`stats: false`); + } + }); +}); diff --git a/test/no-stats/with-config/webpack.config.js b/test/no-stats/with-config/webpack.config.js new file mode 100644 index 00000000000..60033b6bffd --- /dev/null +++ b/test/no-stats/with-config/webpack.config.js @@ -0,0 +1,9 @@ +// eslint-disable-next-line node/no-unpublished-require +const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin'); + +module.exports = { + mode: 'development', + entry: './main.js', + stats: 'detailed', + plugins: [new WebpackCLITestPlugin()], +}; diff --git a/test/no-stats/with-flags/main.js b/test/no-stats/with-flags/main.js new file mode 100644 index 00000000000..0a41cfe5c6e --- /dev/null +++ b/test/no-stats/with-flags/main.js @@ -0,0 +1,4 @@ +require('url'); +require('path'); + +console.log('--no-stats test'); diff --git a/test/no-stats/with-flags/no-stats.test.js b/test/no-stats/with-flags/no-stats.test.js new file mode 100644 index 00000000000..13ecdf7b20b --- /dev/null +++ b/test/no-stats/with-flags/no-stats.test.js @@ -0,0 +1,51 @@ +'use strict'; +// eslint-disable-next-line node/no-unpublished-require +const { run } = require('../../utils/test-utils'); +// eslint-disable-next-line node/no-extraneous-require +const { version } = require('webpack'); + +describe('stats flag', () => { + it('should accept --no-stats as boolean', () => { + const { stderr, stdout } = run(__dirname, ['--no-stats']); + + expect(stderr).toBeFalsy(); + if (version.startsWith('5')) { + expect(stdout).toContain(`stats: { preset: 'none' }`); + } else { + expect(stdout).toContain('stats: false'); + } + }); + + it('should warn and use --no-stats when stats and no-stats both are provided', () => { + const { stderr, stdout } = run(__dirname, ['--stats', 'verbose', '--no-stats']); + + expect(stderr).toContain(`You provided both --stats and --no-stats. We will use only the last of these flags`); + if (version.startsWith('5')) { + expect(stdout).toContain(`stats: { preset: 'none' }`); + } else { + expect(stdout).toContain('stats: false'); + } + }); + + it('should warn and use --stats when stats and no-stats both are provided', () => { + const { stderr, stdout } = run(__dirname, ['--no-stats', '--stats', 'verbose']); + + expect(stderr).toContain(`You provided both --stats and --no-stats. We will use only the last of these flags`); + if (version.startsWith('5')) { + expect(stdout).toContain(`stats: { preset: 'verbose' }`); + } else { + expect(stdout).toContain(`stats: 'verbose'`); + } + }); + + it('should use --verbose over --no-stats', () => { + const { stderr, stdout } = run(__dirname, ['--no-stats', '--verbose']); + + expect(stderr).toBeFalsy(); + if (version.startsWith('5')) { + expect(stdout).toContain(`stats: { preset: 'verbose' }`); + } else { + expect(stdout).toContain(`stats: 'verbose'`); + } + }); +}); diff --git a/test/no-stats/with-flags/webpack.config.js b/test/no-stats/with-flags/webpack.config.js new file mode 100644 index 00000000000..a922c06f2b2 --- /dev/null +++ b/test/no-stats/with-flags/webpack.config.js @@ -0,0 +1,8 @@ +// eslint-disable-next-line node/no-unpublished-require +const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin'); + +module.exports = { + mode: 'development', + entry: './main.js', + plugins: [new WebpackCLITestPlugin()], +}; diff --git a/test/serve/basic/serve-basic.test.js b/test/serve/basic/serve-basic.test.js index ddaca288ade..ccb1a8e8f19 100644 --- a/test/serve/basic/serve-basic.test.js +++ b/test/serve/basic/serve-basic.test.js @@ -23,6 +23,13 @@ describe('basic serve usage', () => { console.warn('TODO: fix `serve` test on windows'); }); } else { + it('should not invoke info subcommand', async () => { + const { stdout, stderr } = await runServe(['--client-log-level', 'info'], testPath); + expect(stdout).toContain('main.js'); + expect(stdout).not.toContain('hot/dev-server.js'); + expect(stderr).toHaveLength(0); + }); + it('compiles without flags', async () => { const { stdout, stderr } = await runServe(['--port', port], testPath); expect(stdout).toContain('main.js'); diff --git a/test/stats/cli-flags/stats.test.js b/test/stats/cli-flags/stats.test.js index dc3d37ac515..3dab024c937 100644 --- a/test/stats/cli-flags/stats.test.js +++ b/test/stats/cli-flags/stats.test.js @@ -23,7 +23,7 @@ describe('stats flag', () => { const { stderr, stdout } = run(__dirname, ['--stats']); expect(stderr).toBeFalsy(); if (version.startsWith('5')) { - expect(stdout).toContain(`stats: {}`); + expect(stdout).toContain(`stats: { preset: 'normal' }`); } else { expect(stdout).toContain('stats: true'); }