From 08aaff3ccc249749da742e2e9c0bb09f82cc1001 Mon Sep 17 00:00:00 2001 From: James George Date: Wed, 19 Aug 2020 15:46:14 +0530 Subject: [PATCH 1/7] refactor: cliExecuter consumes runCLI (#1754) --- packages/webpack-cli/__tests__/cli-executer.test.js | 10 +++++----- packages/webpack-cli/lib/runner.js | 10 ---------- packages/webpack-cli/lib/utils/cli-executer.js | 4 ++-- 3 files changed, 7 insertions(+), 17 deletions(-) delete mode 100644 packages/webpack-cli/lib/runner.js diff --git a/packages/webpack-cli/__tests__/cli-executer.test.js b/packages/webpack-cli/__tests__/cli-executer.test.js index a67b63bc293..74bdde7c346 100644 --- a/packages/webpack-cli/__tests__/cli-executer.test.js +++ b/packages/webpack-cli/__tests__/cli-executer.test.js @@ -1,8 +1,8 @@ -jest.mock('../lib/runner'); +jest.mock('../lib/bootstrap'); jest.mock('enquirer'); -const runner = require('../lib/runner'); -runner.mockImplementation(() => {}); +const runCLI = require('../lib/bootstrap'); +runCLI.mockImplementation(() => {}); describe('CLI Executer', () => { let cliExecuter = null; @@ -48,8 +48,8 @@ describe('CLI Executer', () => { await cliExecuter(); // ensure that the webpack runCLI is called - expect(runner.mock.calls.length).toEqual(1); - expect(runner.mock.calls[0]).toEqual([[], ['--config', 'test1', '--entry', 'test2', '--progress']]); + expect(runCLI.mock.calls.length).toEqual(1); + expect(runCLI.mock.calls[0][0]).toEqual(['--config', 'test1', '--entry', 'test2', '--progress']); // check that webpack options are actually being displayed that // the user can select from diff --git a/packages/webpack-cli/lib/runner.js b/packages/webpack-cli/lib/runner.js deleted file mode 100644 index 50295954e04..00000000000 --- a/packages/webpack-cli/lib/runner.js +++ /dev/null @@ -1,10 +0,0 @@ -const execa = require('execa'); -const cliPath = require.resolve('./bootstrap.js'); - -function runner(nodeArgs, cliArgs) { - execa('node', [...nodeArgs, cliPath, ...cliArgs], { stdio: 'inherit' }).catch((e) => { - process.exit(e.exitCode); - }); -} - -module.exports = runner; diff --git a/packages/webpack-cli/lib/utils/cli-executer.js b/packages/webpack-cli/lib/utils/cli-executer.js index fbb2ef6895c..8c4a89cd95b 100644 --- a/packages/webpack-cli/lib/utils/cli-executer.js +++ b/packages/webpack-cli/lib/utils/cli-executer.js @@ -2,7 +2,7 @@ const { MultiSelect, Input } = require('enquirer'); const { cyan } = require('colorette'); const logger = require('./logger'); const cliArgs = require('./cli-flags').core; -const runner = require('../runner'); +const runCLI = require('../bootstrap'); async function prompter() { const args = []; @@ -56,7 +56,7 @@ async function run() { const args = await prompter(); process.stdout.write('\n'); logger.info('Executing CLI\n'); - await runner([], args); + await runCLI(args); } catch (err) { logger.error(`Action Interrupted, use ${cyan('webpack-cli help')} to see possible options.`); } From 83f73b056e224301b871bee5e9b7254e64e84e95 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Wed, 19 Aug 2020 15:50:55 +0530 Subject: [PATCH 2/7] fix: use appropriate exit codes (#1755) --- README.md | 9 +++++++++ packages/package-utils/__tests__/packageUtils.test.ts | 2 +- packages/package-utils/src/packageUtils.ts | 2 +- packages/utils/src/modify-config-helper.ts | 6 +++--- packages/utils/src/npm-packages-exists.ts | 2 +- packages/webpack-cli/lib/groups/HelpGroup.js | 4 ++-- packages/webpack-cli/lib/utils/process-log.js | 2 +- 7 files changed, 18 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b65ccaf496a..7d69c4b4bf9 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ - [Utilities](#utilities) - [Getting started](#getting-started) - [webpack CLI Scaffolds](#webpack-cli-scaffolds) +- [Exit codes and their meanings](#exit-codes-and-their-meanings) - [Contributing and Internal Documentation](#contributing-and-internal-documentation) - [Open Collective](#open-collective) @@ -96,6 +97,14 @@ With v3 of webpack CLI, we introduced scaffolding as an integral part of the CLI You can read more about [Scaffolding](https://webpack.js.org/guides/scaffolding), learn [How to compose a webpack-scaffold?](https://webpack.js.org/contribute/writing-a-scaffold) or generate one with [webpack-scaffold-starter](https://github.com/rishabh3112/webpack-scaffold-starter). +## Exit codes and their meanings + +| Exit Code | Description | +| --------- | -------------------------------------------------- | +| `0` | Success | +| `1` | Warnings/Errors from webpack | +| `2` | Configuration/options problem or an internal error | + ## Contributing and Internal Documentation The webpack family welcomes any contributor, small or big. We are happy to elaborate, guide you through the source code and find issues you might want to work on! To get started have a look at our [documentation on contributing](./.github/CONTRIBUTING.md). diff --git a/packages/package-utils/__tests__/packageUtils.test.ts b/packages/package-utils/__tests__/packageUtils.test.ts index 64bba4600b1..e853fa2ac0a 100644 --- a/packages/package-utils/__tests__/packageUtils.test.ts +++ b/packages/package-utils/__tests__/packageUtils.test.ts @@ -177,7 +177,7 @@ describe('packageUtils', () => { // runCommand should not be called, because the installation is not confirmed expect((runCommand as jest.Mock).mock.calls.length).toEqual(0); expect((prompt as jest.Mock).mock.calls[0][0][0].message).toMatch(/Would you like to install test-package\?/); - expect(process.exitCode).toEqual(-1); + expect(process.exitCode).toEqual(2); }); }); }); diff --git a/packages/package-utils/src/packageUtils.ts b/packages/package-utils/src/packageUtils.ts index 09b9f0330f5..167d7bee322 100644 --- a/packages/package-utils/src/packageUtils.ts +++ b/packages/package-utils/src/packageUtils.ts @@ -98,5 +98,5 @@ export async function promptInstallation(packageName: string, preMessage?: Funct return exports.packageExists(packageName); } // eslint-disable-next-line require-atomic-updates - process.exitCode = -1; + process.exitCode = 2; } diff --git a/packages/utils/src/modify-config-helper.ts b/packages/utils/src/modify-config-helper.ts index eb3681b0d3f..913d0d21e84 100644 --- a/packages/utils/src/modify-config-helper.ts +++ b/packages/utils/src/modify-config-helper.ts @@ -86,7 +86,7 @@ export function modifyHelperUtil( } catch (err) { console.error(red('\nYour package.json was incorrectly formatted.\n')); Error.stackTraceLimit = 0; - process.exitCode = -1; + process.exitCode = 2; } env.registerStub(generator, generatorName); @@ -108,7 +108,7 @@ export function modifyHelperUtil( red("\nPlease make sure to use 'this.config.set('configuration', this.configuration);' at the end of the generator.\n"), ); Error.stackTraceLimit = 0; - process.exitCode = -1; + process.exitCode = 2; } try { // the configuration stored in .yo-rc.json should already be in the correct @@ -126,7 +126,7 @@ export function modifyHelperUtil( red('\nYour yeoman configuration file (.yo-rc.json) was incorrectly formatted. Deleting it may fix the problem.\n'), ); Error.stackTraceLimit = 0; - process.exitCode = -1; + process.exitCode = 2; } const transformConfig = Object.assign( diff --git a/packages/utils/src/npm-packages-exists.ts b/packages/utils/src/npm-packages-exists.ts index a5b3d4b7d11..3233a8027bb 100644 --- a/packages/utils/src/npm-packages-exists.ts +++ b/packages/utils/src/npm-packages-exists.ts @@ -61,7 +61,7 @@ export function npmPackagesExists(pkg: string[]): void { .catch((err: Error): void => { console.error(err.stack || err); // eslint-disable-next-line no-process-exit - process.exit(0); + process.exit(2); }) .then(resolvePackagesIfReady); }); diff --git a/packages/webpack-cli/lib/groups/HelpGroup.js b/packages/webpack-cli/lib/groups/HelpGroup.js index c78612e8b54..b72ab8ea325 100644 --- a/packages/webpack-cli/lib/groups/HelpGroup.js +++ b/packages/webpack-cli/lib/groups/HelpGroup.js @@ -58,13 +58,13 @@ class HelpGroup { } } catch (e) { logger.error('Error: External package not found.'); - process.exitCode = 1; + process.exit(2); } } if (commandsUsed.length > 1) { logger.error('You provided multiple commands. Please use only one command at a time.\n'); - process.exit(1); + process.exit(2); } if (invalidArgs.length > 0) { diff --git a/packages/webpack-cli/lib/utils/process-log.js b/packages/webpack-cli/lib/utils/process-log.js index 17dfa0a263f..45933841849 100644 --- a/packages/webpack-cli/lib/utils/process-log.js +++ b/packages/webpack-cli/lib/utils/process-log.js @@ -2,7 +2,7 @@ const logger = require('./logger'); function logErrorAndExit(error) { if (error && error.stack) logger.error(error.stack); - process.exit(1); + process.exit(error.exitCode); } process.on('uncaughtException', (error) => { From d3ed19a96811b98caa0ea0de0f8d7e76fe06879d Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Wed, 19 Aug 2020 16:23:07 +0530 Subject: [PATCH 3/7] feat: add --config-name flag (#1753) --- packages/webpack-cli/README.md | 1 + .../webpack-cli/lib/groups/ConfigGroup.js | 11 +++++ packages/webpack-cli/lib/utils/cli-flags.js | 8 ++++ test/config-name/config-name.test.js | 46 +++++++++++++++++++ test/config-name/src/first.js | 1 + test/config-name/src/second.js | 1 + test/config-name/src/third.js | 1 + test/config-name/webpack.config.js | 26 +++++++++++ 8 files changed, 95 insertions(+) create mode 100644 test/config-name/config-name.test.js create mode 100644 test/config-name/src/first.js create mode 100644 test/config-name/src/second.js create mode 100644 test/config-name/src/third.js create mode 100644 test/config-name/webpack.config.js diff --git a/packages/webpack-cli/README.md b/packages/webpack-cli/README.md index 4751e251fec..637ac81ea74 100644 --- a/packages/webpack-cli/README.md +++ b/packages/webpack-cli/README.md @@ -38,6 +38,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 + --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 --color Enables colors on console diff --git a/packages/webpack-cli/lib/groups/ConfigGroup.js b/packages/webpack-cli/lib/groups/ConfigGroup.js index 5e8953759be..fbfc3b4ccd4 100644 --- a/packages/webpack-cli/lib/groups/ConfigGroup.js +++ b/packages/webpack-cli/lib/groups/ConfigGroup.js @@ -5,6 +5,7 @@ const { extensions, jsVariants } = require('interpret'); const GroupHelper = require('../utils/GroupHelper'); const rechoir = require('rechoir'); const MergeError = require('../utils/errors/MergeError'); +const logger = require('../utils/logger'); // 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 @@ -117,6 +118,16 @@ class ConfigGroup extends GroupHelper { const newOptions = configOptions(formattedEnv, argv); // When config function returns a promise, resolve it, if not it's resolved by default newOptionsObject['options'] = await Promise.resolve(newOptions); + } else if (Array.isArray(configOptions) && this.args.configName) { + // In case of exporting multiple configurations, If you pass a name to --config-name flag, + // webpack will only build that specific configuration. + const namedOptions = configOptions.filter((opt) => this.args.configName.includes(opt.name)); + if (namedOptions.length === 0) { + logger.error(`Configuration with name "${this.args.configName}" was not found.`); + process.exit(2); + } else { + newOptionsObject['options'] = namedOptions; + } } else { if (Array.isArray(configOptions) && !configOptions.length) { newOptionsObject['options'] = {}; diff --git a/packages/webpack-cli/lib/utils/cli-flags.js b/packages/webpack-cli/lib/utils/cli-flags.js index b11a1debb08..0e4afea8193 100644 --- a/packages/webpack-cli/lib/utils/cli-flags.js +++ b/packages/webpack-cli/lib/utils/cli-flags.js @@ -124,6 +124,14 @@ module.exports = { description: 'Provide path to a webpack configuration file e.g. ./webpack.config.js', link: 'https://webpack.js.org/configuration/', }, + { + name: 'config-name', + usage: '--config-name ', + type: String, + multiple: true, + group: CONFIG_GROUP, + description: 'Name of the configuration to use', + }, { name: 'color', usage: '--color', diff --git a/test/config-name/config-name.test.js b/test/config-name/config-name.test.js new file mode 100644 index 00000000000..53b66537ecf --- /dev/null +++ b/test/config-name/config-name.test.js @@ -0,0 +1,46 @@ +'use strict'; + +const { run } = require('../utils/test-utils'); +const { stat } = require('fs'); +const { resolve } = require('path'); + +describe('--config-name flag', () => { + it('should select only the config whose name is passed with --config-name', (done) => { + const { stderr, stdout } = run(__dirname, ['--config-name', 'first'], false); + expect(stderr).toBeFalsy(); + expect(stdout).toContain('Child first'); + expect(stdout).not.toContain('Child second'); + expect(stdout).not.toContain('Child third'); + + stat(resolve(__dirname, './dist/dist-first.js'), (err, stats) => { + expect(err).toBe(null); + expect(stats.isFile()).toBe(true); + done(); + }); + }); + + it('should work with multiple values for --config-name', (done) => { + const { stderr, stdout } = run(__dirname, ['--config-name', 'first', '--config-name', 'third'], false); + expect(stderr).toBeFalsy(); + expect(stdout).toContain('Child first'); + expect(stdout).not.toContain('Child second'); + expect(stdout).toContain('Child third'); + + stat(resolve(__dirname, './dist/dist-first.js'), (err, stats) => { + expect(err).toBe(null); + expect(stats.isFile()).toBe(true); + done(); + }); + stat(resolve(__dirname, './dist/dist-third.js'), (err, stats) => { + expect(err).toBe(null); + expect(stats.isFile()).toBe(true); + done(); + }); + }); + + it('should log error if invalid config name is provided', () => { + const { stderr, stdout } = run(__dirname, ['--config-name', 'test'], false); + expect(stderr).toContain('Configuration with name "test" was not found.'); + expect(stdout).toBeFalsy(); + }); +}); diff --git a/test/config-name/src/first.js b/test/config-name/src/first.js new file mode 100644 index 00000000000..3dfd0a1def0 --- /dev/null +++ b/test/config-name/src/first.js @@ -0,0 +1 @@ +console.log('first config'); diff --git a/test/config-name/src/second.js b/test/config-name/src/second.js new file mode 100644 index 00000000000..15c0f734c34 --- /dev/null +++ b/test/config-name/src/second.js @@ -0,0 +1 @@ +console.log('second config'); diff --git a/test/config-name/src/third.js b/test/config-name/src/third.js new file mode 100644 index 00000000000..1047ae56bdc --- /dev/null +++ b/test/config-name/src/third.js @@ -0,0 +1 @@ +console.log('third config'); diff --git a/test/config-name/webpack.config.js b/test/config-name/webpack.config.js new file mode 100644 index 00000000000..515d077d3e2 --- /dev/null +++ b/test/config-name/webpack.config.js @@ -0,0 +1,26 @@ +module.exports = [ + { + output: { + filename: './dist-first.js', + }, + name: 'first', + entry: './src/first.js', + mode: 'development', + }, + { + output: { + filename: './dist-second.js', + }, + name: 'second', + entry: './src/second.js', + mode: 'production', + }, + { + output: { + filename: './dist-third.js', + }, + name: 'third', + entry: './src/third.js', + mode: 'none', + }, +]; From 5b49061c118706d814aadda90e6b84f872c7648e Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Wed, 19 Aug 2020 19:37:24 +0530 Subject: [PATCH 4/7] tests: loader's tests for errors and warnings (#1736) * tests: loader's error regression test for #1581 * tests: add test on error code * tests: add tests in case of warnings from loader Co-authored-by: Anshuman Verma --- .gitignore | 1 + packages/webpack-cli/lib/utils/Compiler.js | 6 ++-- test/loader/error-test/loader-error.test.js | 15 ++++++++++ test/loader/error-test/package.json | 6 ++++ test/loader/error-test/src/index.ts | 4 +++ test/loader/error-test/webpack.config.js | 25 ++++++++++++++++ .../warning-test/loader-warning.test.js | 13 ++++++++ test/loader/warning-test/my-loader.js | 5 ++++ test/loader/warning-test/src/main.js | 2 ++ test/loader/warning-test/webpack.config.js | 30 +++++++++++++++++++ 10 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 test/loader/error-test/loader-error.test.js create mode 100644 test/loader/error-test/package.json create mode 100644 test/loader/error-test/src/index.ts create mode 100644 test/loader/error-test/webpack.config.js create mode 100644 test/loader/warning-test/loader-warning.test.js create mode 100644 test/loader/warning-test/my-loader.js create mode 100644 test/loader/warning-test/src/main.js create mode 100644 test/loader/warning-test/webpack.config.js diff --git a/.gitignore b/.gitignore index b15f3b3364e..f5a5b47b8dc 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,4 @@ packages/**/*.map # temporary test files test-assets/ +./lib/ diff --git a/packages/webpack-cli/lib/utils/Compiler.js b/packages/webpack-cli/lib/utils/Compiler.js index a3adc89b3e9..89c6b7126d2 100644 --- a/packages/webpack-cli/lib/utils/Compiler.js +++ b/packages/webpack-cli/lib/utils/Compiler.js @@ -80,6 +80,9 @@ class Compiler { logger.error(err.stack || err); process.exit(1); // eslint-disable-line } + if (!outputOptions.watch && (stats.hasErrors() || stats.hasWarnings())) { + process.exitCode = 1; + } if (outputOptions.json) { process.stdout.write(JSON.stringify(stats.toJson(outputOptions), null, 2) + '\n'); } else if (stats.hash !== lastHash) { @@ -93,9 +96,6 @@ class Compiler { } return this.generateOutput(outputOptions, stats, statsErrors, processingMessageBuffer); } - if (!outputOptions.watch && stats.hasErrors()) { - process.exitCode = 2; - } } async invokeCompilerInstance(lastHash, options, outputOptions, processingMessageBuffer) { diff --git a/test/loader/error-test/loader-error.test.js b/test/loader/error-test/loader-error.test.js new file mode 100644 index 00000000000..38d0ab29eef --- /dev/null +++ b/test/loader/error-test/loader-error.test.js @@ -0,0 +1,15 @@ +'use strict'; + +// eslint-disable-next-line node/no-unpublished-require +const { run } = require('../../utils/test-utils'); + +describe('loader error regression test for #1581', () => { + it(`should not ignore loader's error produce a failing build`, () => { + // Ignoring assertion on stderr because ts-loader is producing depreciation warnings + // with webpack@v5.0.0-beta.24 -> https://github.com/TypeStrong/ts-loader/issues/1169 + const { stdout, exitCode } = run(__dirname, [], false); + expect(exitCode).not.toEqual(0); + expect(stdout).toContain('[1 error]'); + expect(stdout).toContain(`Cannot assign to 'foobar' because it is a constant`); + }); +}); diff --git a/test/loader/error-test/package.json b/test/loader/error-test/package.json new file mode 100644 index 00000000000..ff851c60c4f --- /dev/null +++ b/test/loader/error-test/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "ts-loader": "^7.0.5", + "typescript": "^3.9.3" + } +} diff --git a/test/loader/error-test/src/index.ts b/test/loader/error-test/src/index.ts new file mode 100644 index 00000000000..39967926fa2 --- /dev/null +++ b/test/loader/error-test/src/index.ts @@ -0,0 +1,4 @@ +const foobar = 'foobar'; +// eslint-disable-next-line no-const-assign +foobar = 'barbaz'; // Error! +console.log(foobar); diff --git a/test/loader/error-test/webpack.config.js b/test/loader/error-test/webpack.config.js new file mode 100644 index 00000000000..5aca8bbcd77 --- /dev/null +++ b/test/loader/error-test/webpack.config.js @@ -0,0 +1,25 @@ +const path = require('path'); + +module.exports = { + mode: 'development', + + entry: { + bundle: './src/index.ts', + }, + + output: { + path: path.resolve(__dirname, 'dist'), + filename: '[name].js', + }, + + module: { + rules: [ + { + test: /.(ts|tsx)?$/, + loader: 'ts-loader', + include: [path.resolve(__dirname, 'src')], + exclude: [/node_modules/], + }, + ], + }, +}; diff --git a/test/loader/warning-test/loader-warning.test.js b/test/loader/warning-test/loader-warning.test.js new file mode 100644 index 00000000000..106e6afb8b0 --- /dev/null +++ b/test/loader/warning-test/loader-warning.test.js @@ -0,0 +1,13 @@ +'use strict'; + +const { run } = require('../../utils/test-utils'); + +describe('loader warning test', () => { + it(`should not ignore loader's warning and exit with a non zero exit code`, () => { + const { stdout, exitCode } = run(__dirname, [], false); + + expect(stdout).toContain('[1 warning]'); + expect(stdout).toContain('This is a warning'); + expect(exitCode).not.toEqual(0); + }); +}); diff --git a/test/loader/warning-test/my-loader.js b/test/loader/warning-test/my-loader.js new file mode 100644 index 00000000000..042520fc4a4 --- /dev/null +++ b/test/loader/warning-test/my-loader.js @@ -0,0 +1,5 @@ +module.exports = function loader(source) { + const { emitWarning } = this; + emitWarning('This is a warning'); + return source; +}; diff --git a/test/loader/warning-test/src/main.js b/test/loader/warning-test/src/main.js new file mode 100644 index 00000000000..fbcad03c6af --- /dev/null +++ b/test/loader/warning-test/src/main.js @@ -0,0 +1,2 @@ +require('../my-loader'); +console.log('loader warning test'); diff --git a/test/loader/warning-test/webpack.config.js b/test/loader/warning-test/webpack.config.js new file mode 100644 index 00000000000..ce43c65a673 --- /dev/null +++ b/test/loader/warning-test/webpack.config.js @@ -0,0 +1,30 @@ +const path = require('path'); + +module.exports = { + mode: 'development', + + entry: { + bundle: './src/main.js', + }, + + output: { + path: path.resolve(__dirname, 'dist'), + filename: '[name].js', + }, + + module: { + rules: [ + { + test: /.(js|jsx)?$/, + loader: 'my-loader', + include: [path.resolve(__dirname, 'src')], + exclude: [/node_modules/], + }, + ], + }, + resolveLoader: { + alias: { + 'my-loader': require.resolve('./my-loader'), + }, + }, +}; From b071623ae67a9f9528b02e07376044d851ad378a Mon Sep 17 00:00:00 2001 From: Anshuman Verma Date: Wed, 19 Aug 2020 20:49:34 +0530 Subject: [PATCH 5/7] fix: allow unknown files to use default require as fallback (#1747) --- .../webpack-cli/lib/groups/ConfigGroup.js | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/packages/webpack-cli/lib/groups/ConfigGroup.js b/packages/webpack-cli/lib/groups/ConfigGroup.js index fbfc3b4ccd4..3ddf1875ad8 100644 --- a/packages/webpack-cli/lib/groups/ConfigGroup.js +++ b/packages/webpack-cli/lib/groups/ConfigGroup.js @@ -1,5 +1,5 @@ const { existsSync } = require('fs'); -const { resolve, sep, dirname, parse } = require('path'); +const { resolve, sep, dirname, extname } = require('path'); const webpackMerge = require('webpack-merge'); const { extensions, jsVariants } = require('interpret'); const GroupHelper = require('../utils/GroupHelper'); @@ -42,25 +42,16 @@ const getDefaultConfigFiles = () => { }; const getConfigInfoFromFileName = (filename) => { - const fileMetaData = parse(filename); - // .cjs is not available on interpret side, handle it manually for now - if (filename.endsWith('.cjs')) { - return [ - { - path: resolve(filename), - ext: '.cjs', - module: null, - }, - ]; - } - return Object.keys(extensions) - .filter((ext) => ext.includes(fileMetaData.ext)) - .filter((ext) => fileMetaData.base.substr(fileMetaData.base.length - ext.length) === ext) - .map((ext) => { + const ext = extname(filename); + // since we support only one config for now + const allFiles = [filename]; + // return all the file metadata + return allFiles + .map((file) => { return { - path: resolve(filename), + path: resolve(file), ext: ext, - module: extensions[ext], + module: extensions[ext] || null, }; }) .filter((e) => existsSync(e.path)); From 86dfe514a5b5de38f631a02e5211d10f32c536b9 Mon Sep 17 00:00:00 2001 From: Anshuman Verma Date: Thu, 20 Aug 2020 16:06:22 +0530 Subject: [PATCH 6/7] fix: throw err when supplied config is absent (#1760) --- .../webpack-cli/lib/groups/ConfigGroup.js | 11 +++------- packages/webpack-cli/lib/utils/Compiler.js | 20 +++++++++---------- packages/webpack-cli/lib/utils/GroupHelper.js | 1 - .../lib/utils/errors/ConfigError.js | 11 ++++++++++ .../lib/utils/errors/MergeError.js | 10 ---------- packages/webpack-cli/lib/utils/interactive.js | 6 +++--- packages/webpack-cli/lib/webpack-cli.js | 16 --------------- test/config/absent/a.js | 1 + test/config/absent/config-absent.test.js | 18 +++++++++++++++++ test/config/absent/webpack.config-absent.js | 9 +++++++++ 10 files changed, 55 insertions(+), 48 deletions(-) create mode 100644 packages/webpack-cli/lib/utils/errors/ConfigError.js delete mode 100644 packages/webpack-cli/lib/utils/errors/MergeError.js create mode 100644 test/config/absent/a.js create mode 100644 test/config/absent/config-absent.test.js create mode 100644 test/config/absent/webpack.config-absent.js diff --git a/packages/webpack-cli/lib/groups/ConfigGroup.js b/packages/webpack-cli/lib/groups/ConfigGroup.js index 3ddf1875ad8..09f4cea3f3b 100644 --- a/packages/webpack-cli/lib/groups/ConfigGroup.js +++ b/packages/webpack-cli/lib/groups/ConfigGroup.js @@ -4,7 +4,7 @@ const webpackMerge = require('webpack-merge'); const { extensions, jsVariants } = require('interpret'); const GroupHelper = require('../utils/GroupHelper'); const rechoir = require('rechoir'); -const MergeError = require('../utils/errors/MergeError'); +const ConfigError = require('../utils/errors/ConfigError'); const logger = require('../utils/logger'); // Order defines the priority, in increasing order @@ -89,7 +89,6 @@ class ConfigGroup extends GroupHelper { const newOptionsObject = { outputOptions: {}, options: {}, - processingMessageBuffer: [], }; if (!moduleObj) { @@ -148,11 +147,7 @@ class ConfigGroup extends GroupHelper { const configPath = resolve(process.cwd(), config); const configFiles = getConfigInfoFromFileName(configPath); if (!configFiles.length) { - this.opts.processingMessageBuffer.push({ - lvl: 'warn', - msg: `Configuration ${config} not found in ${configPath}`, - }); - return; + throw new ConfigError(`The specified config file doesn't exist in ${configPath}`); } const foundConfig = configFiles[0]; const resolvedConfig = this.requireConfig(foundConfig); @@ -187,7 +182,7 @@ class ConfigGroup extends GroupHelper { const newConfigPath = this.resolveFilePath(merge); if (!newConfigPath) { - throw new MergeError("The supplied merge config doesn't exist."); + throw new ConfigError("The supplied merge config doesn't exist.", 'MergeError'); } const configFiles = getConfigInfoFromFileName(newConfigPath); diff --git a/packages/webpack-cli/lib/utils/Compiler.js b/packages/webpack-cli/lib/utils/Compiler.js index 89c6b7126d2..691bff79e0a 100644 --- a/packages/webpack-cli/lib/utils/Compiler.js +++ b/packages/webpack-cli/lib/utils/Compiler.js @@ -68,7 +68,7 @@ class Compiler { } } - compilerCallback(err, stats, lastHash, options, outputOptions, processingMessageBuffer) { + compilerCallback(err, stats, lastHash, options, outputOptions) { const statsErrors = []; if (!outputOptions.watch || err) { @@ -94,23 +94,23 @@ class Compiler { statsErrors.push({ name: statErr.message, loc: errLoc }); }); } - return this.generateOutput(outputOptions, stats, statsErrors, processingMessageBuffer); + return this.generateOutput(outputOptions, stats, statsErrors); } } - async invokeCompilerInstance(lastHash, options, outputOptions, processingMessageBuffer) { + async invokeCompilerInstance(lastHash, options, outputOptions) { // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve) => { await this.compiler.run((err, stats) => { - const content = this.compilerCallback(err, stats, lastHash, options, outputOptions, processingMessageBuffer); + const content = this.compilerCallback(err, stats, lastHash, options, outputOptions); resolve(content); }); }); } - async invokeWatchInstance(lastHash, options, outputOptions, watchOptions, processingMessageBuffer) { + async invokeWatchInstance(lastHash, options, outputOptions, watchOptions) { return this.compiler.watch(watchOptions, (err, stats) => { - return this.compilerCallback(err, stats, lastHash, options, outputOptions, processingMessageBuffer); + return this.compilerCallback(err, stats, lastHash, options, outputOptions); }); } @@ -131,7 +131,7 @@ class Compiler { } async webpackInstance(opts) { - const { outputOptions, processingMessageBuffer, options } = opts; + const { outputOptions, options } = opts; const lastHash = null; const { ProgressPlugin } = webpack; @@ -141,7 +141,7 @@ class Compiler { if (outputOptions.interactive) { const interactive = require('./interactive'); - return interactive(options, outputOptions, processingMessageBuffer); + return interactive(options, outputOptions); } if (this.compiler.compilers) { @@ -160,9 +160,9 @@ class Compiler { }); process.stdin.resume(); } - await this.invokeWatchInstance(lastHash, options, outputOptions, watchOptions, processingMessageBuffer); + await this.invokeWatchInstance(lastHash, options, outputOptions, watchOptions); } else { - return await this.invokeCompilerInstance(lastHash, options, outputOptions, processingMessageBuffer); + return await this.invokeCompilerInstance(lastHash, options, outputOptions); } } } diff --git a/packages/webpack-cli/lib/utils/GroupHelper.js b/packages/webpack-cli/lib/utils/GroupHelper.js index e683128e8b1..f7e539533eb 100644 --- a/packages/webpack-cli/lib/utils/GroupHelper.js +++ b/packages/webpack-cli/lib/utils/GroupHelper.js @@ -7,7 +7,6 @@ class GroupHelper { this.opts = { outputOptions: {}, options: {}, - processingMessageBuffer: [], }; this.strategy = undefined; } diff --git a/packages/webpack-cli/lib/utils/errors/ConfigError.js b/packages/webpack-cli/lib/utils/errors/ConfigError.js new file mode 100644 index 00000000000..3a7539c21bc --- /dev/null +++ b/packages/webpack-cli/lib/utils/errors/ConfigError.js @@ -0,0 +1,11 @@ +class ConfigError extends Error { + constructor(message, name) { + super(message); + this.name = name || 'ConfigError'; + // No need to show stack trace for known errors + this.stack = ''; + process.exitCode = 2; + } +} + +module.exports = ConfigError; diff --git a/packages/webpack-cli/lib/utils/errors/MergeError.js b/packages/webpack-cli/lib/utils/errors/MergeError.js deleted file mode 100644 index 74c39efd6e6..00000000000 --- a/packages/webpack-cli/lib/utils/errors/MergeError.js +++ /dev/null @@ -1,10 +0,0 @@ -class MergeError extends Error { - constructor(message) { - super(message); - this.name = 'MergeError'; - // No need to show stack trace for known errors - this.stack = ''; - } -} - -module.exports = MergeError; diff --git a/packages/webpack-cli/lib/utils/interactive.js b/packages/webpack-cli/lib/utils/interactive.js index ba1317291a4..e18b5c3ebbf 100644 --- a/packages/webpack-cli/lib/utils/interactive.js +++ b/packages/webpack-cli/lib/utils/interactive.js @@ -96,7 +96,7 @@ const ENTER_KEY = '\n'; const B_KEY = 'b'; const C_KEY = 'c'; -module.exports = async function (config, outputOptions, processingMessageBuffer) { +module.exports = async function (config, outputOptions) { const stdin = process.stdin; stdin.setEncoding('utf-8'); stdin.setRawMode(true); @@ -104,7 +104,7 @@ module.exports = async function (config, outputOptions, processingMessageBuffer) outputOptions.interactive = false; - const webpackCompilation = await webpack({ options: config, outputOptions, processingMessageBuffer }); + const webpackCompilation = await webpack({ options: config, outputOptions }); /* if(errors) { Hngggg } */ @@ -164,7 +164,7 @@ module.exports = async function (config, outputOptions, processingMessageBuffer) if (state.length) { state.pop(); } - const webpackCompilation = await webpack({ options: config, outputOptions, processingMessageBuffer }); + const webpackCompilation = await webpack({ options: config, outputOptions }); state.push(webpackCompilation); informActions(); isSub = true; diff --git a/packages/webpack-cli/lib/webpack-cli.js b/packages/webpack-cli/lib/webpack-cli.js index a6f6909acf9..26e5cb5929d 100644 --- a/packages/webpack-cli/lib/webpack-cli.js +++ b/packages/webpack-cli/lib/webpack-cli.js @@ -12,7 +12,6 @@ class WebpackCLI extends GroupHelper { this.groupMap = new Map(); this.groups = []; this.args = {}; - this.processingMessageBuffer = []; this.compilation = new Compiler(); this.defaultEntry = 'index'; this.possibleFileNames = [ @@ -186,19 +185,6 @@ class WebpackCLI extends GroupHelper { } } - /** - * Responsible for updating the buffer - * - * @param {string[]} messageBuffer The current buffer message - * @private - * @returns {void} - */ - _mergeProcessingMessageBuffer(messageBuffer) { - if (messageBuffer) { - this.processingMessageBuffer = this.processingMessageBuffer.concat(...messageBuffer); - } - } - /** * It receives a group helper, it runs and it merges its result inside * the file result that will be passed to the compiler @@ -212,7 +198,6 @@ class WebpackCLI extends GroupHelper { const result = await groupHelper.run(); this._mergeOptionsToConfiguration(result.options, groupHelper.strategy); this._mergeOptionsToOutputConfiguration(result.outputOptions); - this._mergeProcessingMessageBuffer(result.processingMessageBuffer); } } @@ -270,7 +255,6 @@ class WebpackCLI extends GroupHelper { const webpack = await this.compilation.webpackInstance({ options: this.compilerConfiguration, outputOptions: this.outputConfiguration, - processingMessageBuffer: this.processingMessageBuffer, }); return webpack; } diff --git a/test/config/absent/a.js b/test/config/absent/a.js new file mode 100644 index 00000000000..8ac1838ebe9 --- /dev/null +++ b/test/config/absent/a.js @@ -0,0 +1 @@ +console.log('Zenitsu'); diff --git a/test/config/absent/config-absent.test.js b/test/config/absent/config-absent.test.js new file mode 100644 index 00000000000..51bbea08355 --- /dev/null +++ b/test/config/absent/config-absent.test.js @@ -0,0 +1,18 @@ +'use strict'; +const { existsSync } = require('fs'); +const { resolve } = require('path'); +const { run } = require('../../utils/test-utils'); + +describe('Config:', () => { + it('supplied config file is absent', () => { + const { stdout, stderr, exitCode } = run(__dirname, ['-c', resolve(__dirname, 'webpack.config.js')], false); + // should throw with correct exit code + expect(exitCode).toBe(2); + expect(stdout).toBeFalsy(); + const configPath = resolve(__dirname, 'webpack.config.js'); + // Should contain the correct error message + expect(stderr).toContain(`ConfigError: The specified config file doesn't exist in ${configPath}`); + // Should not bundle + expect(existsSync(resolve(__dirname, './binary/a.bundle.js'))).toBeFalsy(); + }); +}); diff --git a/test/config/absent/webpack.config-absent.js b/test/config/absent/webpack.config-absent.js new file mode 100644 index 00000000000..b58f8a91f0d --- /dev/null +++ b/test/config/absent/webpack.config-absent.js @@ -0,0 +1,9 @@ +const { resolve } = require('path'); + +module.exports = { + entry: './a.js', + output: { + path: resolve(__dirname, 'binary'), + filename: 'a.bundle.js', + }, +}; From d8d5fff567ff9e5b66c0e19a082bd99b8eb82556 Mon Sep 17 00:00:00 2001 From: James George Date: Thu, 20 Aug 2020 21:17:23 +0530 Subject: [PATCH 7/7] test: --output flag handles invalid arg (#1751) --- test/info/info-output.test.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/info/info-output.test.js b/test/info/info-output.test.js index 5742d90c4e5..6274574f2c5 100644 --- a/test/info/info-output.test.js +++ b/test/info/info-output.test.js @@ -1,6 +1,8 @@ /* eslint-disable space-before-function-paren */ 'use strict'; +const { red } = require('colorette'); + const { runInfo } = require('../utils/test-utils'); describe('basic info usage', () => { @@ -36,4 +38,10 @@ describe('basic info usage', () => { expect(stdout).toContain('## System:'); expect(stderr).toHaveLength(0); }); + + it('shows a warning if an invalid value is supplied', () => { + const { stdout, stderr } = runInfo(['--output="unknown"'], __dirname); + expect(stderr).toContain(`[webpack-cli] ${red(`"unknown" is not a valid value for output\n`)}`); + expect(stdout).toBeTruthy(); + }); });