diff --git a/package.json b/package.json index f029c615ce4..504d74f5ff9 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "strip-ansi": "^6.0.0", "ts-jest": "^26.4.3", "typescript": "^4.1.3", - "webpack": "^5.17.0", + "webpack": "^5.18.0", "webpack-bundle-analyzer": "^4.3.0", "webpack-dev-server": "^3.11.1", "yeoman-test": "^2.7.0" diff --git a/packages/serve/src/index.ts b/packages/serve/src/index.ts index 5b72fd66a3a..508b5cee234 100644 --- a/packages/serve/src/index.ts +++ b/packages/serve/src/index.ts @@ -113,7 +113,7 @@ class ServeCommand { try { servers = await startDevServer(compiler, devServerOptions, options, logger); } catch (error) { - if (error.name === 'ValidationError') { + if (cli.isValidationError(error)) { logger.error(error.message); } else { logger.error(error); diff --git a/packages/webpack-cli/lib/webpack-cli.js b/packages/webpack-cli/lib/webpack-cli.js index b945f9b189f..0baf614ee13 100644 --- a/packages/webpack-cli/lib/webpack-cli.js +++ b/packages/webpack-cli/lib/webpack-cli.js @@ -1172,7 +1172,13 @@ class WebpackCLI { } } catch (error) { logger.error(`Failed to load '${configPath}' config`); - logger.error(error); + + if (this.isValidationError(error)) { + logger.error(error.message); + } else { + logger.error(error); + } + process.exit(2); } @@ -1602,15 +1608,15 @@ class WebpackCLI { return compiler.options.watchOptions && compiler.options.watchOptions.stdin; } - async createCompiler(options, callback) { - const isValidationError = (error) => { - // https://github.com/webpack/webpack/blob/master/lib/index.js#L267 - // https://github.com/webpack/webpack/blob/v4.44.2/lib/webpack.js#L90 - const ValidationError = this.webpack.ValidationError || this.webpack.WebpackOptionsValidationError; + isValidationError(error) { + // https://github.com/webpack/webpack/blob/master/lib/index.js#L267 + // https://github.com/webpack/webpack/blob/v4.44.2/lib/webpack.js#L90 + const ValidationError = this.webpack.ValidationError || this.webpack.WebpackOptionsValidationError; - return error instanceof ValidationError; - }; + return error instanceof ValidationError || error.name === 'ValidationError'; + } + async createCompiler(options, callback) { let config = await this.resolveConfig(options); config = await this.applyOptions(config, options); @@ -1623,7 +1629,7 @@ class WebpackCLI { config.options, callback ? (error, stats) => { - if (isValidationError(error)) { + if (error && this.isValidationError(error)) { logger.error(error.message); process.exit(2); } @@ -1633,7 +1639,7 @@ class WebpackCLI { : callback, ); } catch (error) { - if (isValidationError(error)) { + if (this.isValidationError(error)) { logger.error(error.message); } else { logger.error(error); diff --git a/test/error/invalid-schema/invalid-schema.test.js b/test/error/invalid-schema/invalid-schema.test.js index cfcb54542da..05c04c8d735 100644 --- a/test/error/invalid-schema/invalid-schema.test.js +++ b/test/error/invalid-schema/invalid-schema.test.js @@ -3,15 +3,23 @@ const { run, isWebpack5 } = require('../../utils/test-utils'); describe('invalid schema', () => { it('should log error on invalid config', () => { - const { exitCode, stderr, stdout } = run(__dirname, ['--config', './webpack.config.mock.js']); + const { exitCode, stderr, stdout } = run(__dirname, ['--config', './webpack.mock.config.js']); expect(exitCode).toEqual(2); expect(stderr).toContain('Invalid configuration object'); expect(stdout).toBeFalsy(); }); + it('should log error on invalid plugin options', () => { + const { exitCode, stderr, stdout } = run(__dirname, ['--config', './webpack.plugin-mock.config.js']); + + expect(exitCode).toEqual(2); + expect(stderr).toContain(isWebpack5 ? 'Invalid options object' : 'Invalid Options'); + expect(stdout).toBeFalsy(); + }); + it('should log error on invalid config using the "bundle" command', () => { - const { exitCode, stderr, stdout } = run(__dirname, ['bundle', '--config', './webpack.config.mock.js']); + const { exitCode, stderr, stdout } = run(__dirname, ['bundle', '--config', './webpack.mock.config.js']); expect(exitCode).toEqual(2); expect(stderr).toContain('Invalid configuration object'); @@ -19,7 +27,7 @@ describe('invalid schema', () => { }); it('should log error on invalid config using the "serve" command', () => { - const { exitCode, stderr, stdout } = run(__dirname, ['serve', '--config', './webpack.config.mock.js']); + const { exitCode, stderr, stdout } = run(__dirname, ['serve', '--config', './webpack.mock.config.js']); expect(exitCode).toEqual(2); expect(stderr).toContain('Invalid configuration object'); @@ -41,6 +49,21 @@ describe('invalid schema', () => { expect(stdout).toBeFalsy(); }); + it('should log error on invalid option using "build" command', () => { + const { exitCode, stderr, stdout } = run(__dirname, ['build', '--mode', 'Yukihira']); + + expect(exitCode).toEqual(2); + + if (isWebpack5) { + expect(stderr).toContain("Invalid value 'Yukihira' for the '--mode' option"); + expect(stderr).toContain("Expected: 'development | production | none'"); + } else { + expect(stderr).toContain('Invalid configuration object'); + } + + expect(stdout).toBeFalsy(); + }); + it('should log error on invalid option using "bundle" command', () => { const { exitCode, stderr, stdout } = run(__dirname, ['bundle', '--mode', 'Yukihira']); @@ -56,6 +79,51 @@ describe('invalid schema', () => { expect(stdout).toBeFalsy(); }); + it('should log error on invalid option using "b" command', () => { + const { exitCode, stderr, stdout } = run(__dirname, ['b', '--mode', 'Yukihira']); + + expect(exitCode).toEqual(2); + + if (isWebpack5) { + expect(stderr).toContain("Invalid value 'Yukihira' for the '--mode' option"); + expect(stderr).toContain("Expected: 'development | production | none'"); + } else { + expect(stderr).toContain('Invalid configuration object'); + } + + expect(stdout).toBeFalsy(); + }); + + it('should log error on invalid option using "watch" command', () => { + const { exitCode, stderr, stdout } = run(__dirname, ['watch', '--mode', 'Yukihira']); + + expect(exitCode).toEqual(2); + + if (isWebpack5) { + expect(stderr).toContain("Invalid value 'Yukihira' for the '--mode' option"); + expect(stderr).toContain("Expected: 'development | production | none'"); + } else { + expect(stderr).toContain('Invalid configuration object'); + } + + expect(stdout).toBeFalsy(); + }); + + it('should log error on invalid option using "w" command', () => { + const { exitCode, stderr, stdout } = run(__dirname, ['w', '--mode', 'Yukihira']); + + expect(exitCode).toEqual(2); + + if (isWebpack5) { + expect(stderr).toContain("Invalid value 'Yukihira' for the '--mode' option"); + expect(stderr).toContain("Expected: 'development | production | none'"); + } else { + expect(stderr).toContain('Invalid configuration object'); + } + + expect(stdout).toBeFalsy(); + }); + it('should log error on invalid option using "server" command', () => { const { exitCode, stderr, stdout } = run(__dirname, ['serve', '--mode', 'Yukihira']); @@ -70,4 +138,19 @@ describe('invalid schema', () => { expect(stdout).toBeFalsy(); }); + + it('should log error on invalid option using "s" command', () => { + const { exitCode, stderr, stdout } = run(__dirname, ['s', '--mode', 'Yukihira']); + + expect(exitCode).toEqual(2); + + if (isWebpack5) { + expect(stderr).toContain("Invalid value 'Yukihira' for the '--mode' option"); + expect(stderr).toContain("Expected: 'development | production | none'"); + } else { + expect(stderr).toContain('Invalid configuration object'); + } + + expect(stdout).toBeFalsy(); + }); }); diff --git a/test/error/invalid-schema/webpack.config.mock.js b/test/error/invalid-schema/webpack.mock.config.js similarity index 100% rename from test/error/invalid-schema/webpack.config.mock.js rename to test/error/invalid-schema/webpack.mock.config.js diff --git a/test/error/invalid-schema/webpack.plugin-mock.config.js b/test/error/invalid-schema/webpack.plugin-mock.config.js new file mode 100644 index 00000000000..24a228b9d92 --- /dev/null +++ b/test/error/invalid-schema/webpack.plugin-mock.config.js @@ -0,0 +1,10 @@ +const webpack = require('webpack'); + +module.exports = { + mode: 'development', + plugins: [ + new webpack.BannerPlugin({ + unknown: 'unknown', + }), + ], +}; diff --git a/yarn.lock b/yarn.lock index 0dbfd643050..a05832ed73a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1895,11 +1895,16 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" -"@types/json-schema@*", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.6": +"@types/json-schema@*", "@types/json-schema@^7.0.3": version "7.0.6" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== +"@types/json-schema@^7.0.6": + version "7.0.7" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" + integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== + "@types/keyv@*": version "3.1.1" resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7" @@ -2863,15 +2868,15 @@ browser-process-hrtime@^1.0.0: integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== browserslist@^4.14.5: - version "4.15.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.15.0.tgz#3d48bbca6a3f378e86102ffd017d9a03f122bdb0" - integrity sha512-IJ1iysdMkGmjjYeRlDU8PQejVwxvVO5QOfXH7ylW31GO6LwNRSmm/SgRXtNsEXqMLl2e+2H5eEJ7sfynF8TCaQ== + version "4.16.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.1.tgz#bf757a2da376b3447b800a16f0f1c96358138766" + integrity sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA== dependencies: - caniuse-lite "^1.0.30001164" + caniuse-lite "^1.0.30001173" colorette "^1.2.1" - electron-to-chromium "^1.3.612" + electron-to-chromium "^1.3.634" escalade "^3.1.1" - node-releases "^1.1.67" + node-releases "^1.1.69" bs-logger@0.x: version "0.2.6" @@ -3066,10 +3071,10 @@ camelcase@^6.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== -caniuse-lite@^1.0.30001164: - version "1.0.30001165" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001165.tgz#32955490d2f60290bb186bb754f2981917fa744f" - integrity sha512-8cEsSMwXfx7lWSUMA2s08z9dIgsnR5NAqjXP23stdsU3AUWkCr/rr4s4OFtHXn5XXr6+7kam3QFVoYyXNPdJPA== +caniuse-lite@^1.0.30001173: + version "1.0.30001180" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001180.tgz#67abcd6d1edf48fa5e7d1e84091d1d65ab76e33b" + integrity sha512-n8JVqXuZMVSPKiPiypjFtDTXc4jWIdjxull0f92WLo7e1MSi3uJ3NvveakSh/aCl1QKFAvIz3vIj0v+0K+FrXw== capture-exit@^2.0.0: version "2.0.0" @@ -4147,10 +4152,10 @@ ejs@^3.0.1: dependencies: jake "^10.6.1" -electron-to-chromium@^1.3.612: - version "1.3.621" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.621.tgz#0bbe2100ef0b28f88d0b1101fbdf433312f69be0" - integrity sha512-FeIuBzArONbAmKmZIsZIFGu/Gc9AVGlVeVbhCq+G2YIl6QkT0TDn2HKN/FMf1btXEB9kEmIuQf3/lBTVAbmFOg== +electron-to-chromium@^1.3.634: + version "1.3.647" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.647.tgz#8f1750ab7a5137f1a9a27f8f4ebdf550e08ae10b" + integrity sha512-Or2Nu8TjkmSywY9hk85K/Y6il28hchlonITz30fkC87qvSNupQl29O12BzDDDTnUFlo6kEIFL2QGSpkZDMxH8g== elegant-spinner@^1.0.1: version "1.0.1" @@ -8019,10 +8024,10 @@ node-preload@^0.2.1: dependencies: process-on-spawn "^1.0.0" -node-releases@^1.1.67: - version "1.1.67" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.67.tgz#28ebfcccd0baa6aad8e8d4d8fe4cbc49ae239c12" - integrity sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg== +node-releases@^1.1.69: + version "1.1.70" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.70.tgz#66e0ed0273aa65666d7fe78febe7634875426a08" + integrity sha512-Slf2s69+2/uAD79pVVQo8uSiC34+g8GWY8UH2Qtqv34ZfhYrxpYpfzs9Js9d6O0mbDmALuxaTlplnBTnSELcrw== nopt@^4.0.1: version "4.0.3" @@ -11072,7 +11077,7 @@ webpack-sources@^2.1.1: source-list-map "^2.0.1" source-map "^0.6.1" -webpack@^5.17.0: +webpack@^5.18.0: version "5.18.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.18.0.tgz#bbcf13094aa0da0534d513f27d7ee72d74e499c6" integrity sha512-RmiP/iy6ROvVe/S+u0TrvL/oOmvP+2+Bs8MWjvBwwY/j82Q51XJyDJ75m0QAGntL1Wx6B//Xc0+4VPP/hlNHmw==