Skip to content

Commit eb7b189

Browse files
authored
feat: new configtest command (#2303)
1 parent 73d3fec commit eb7b189

16 files changed

+197
-18
lines changed

.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ test/typescript/webpack.config.ts
1010
test/config/error-commonjs/syntax-error.js
1111
test/config/error-mjs/syntax-error.mjs
1212
test/config/error-array/webpack.config.js
13+
test/configtest/syntax-error.config.js

.prettierignore

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ test/config/error-mjs/syntax-error.mjs
99
packages/webpack-cli/__tests__/test-assets/.yo-rc.json
1010
test/build-errors/stats.json
1111
packages/**/lib
12+
test/configtest/syntax-error.config.js

OPTIONS.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ Options:
549549
--watch-options-ignored-reset Clear all items provided in configuration. Ignore some files from watching (glob pattern or regexp).
550550
--watch-options-poll <value> `number`: use polling with specified interval. `true`: use polling.
551551
--watch-options-stdin Stop watching when stdin stream has ended.
552-
--no-watch-options-stdin Negative 'watch-options-stdin' option.
552+
--no-watch-options-stdin Do not stop watching when stdin stream has ended.
553553
554554
Global options:
555555
--color Enable colors on console.
@@ -559,14 +559,15 @@ Global options:
559559
560560
Commands:
561561
bundle|b [options] Run webpack (default command, can be omitted).
562-
help|h Display help for commands and options.
563562
version|v Output the version number of 'webpack', 'webpack-cli' and 'webpack-dev-server' and commands.
563+
help|h Display help for commands and options.
564564
serve|s [options] Run the webpack dev server.
565565
info|i [options] Outputs information about your system.
566566
init|c [options] [scaffold...] Initialize a new webpack configuration.
567567
loader|l [output-path] Scaffold a loader.
568-
plugin|p [output-path] Scaffold a plugin.
569568
migrate|m <config-path> [new-config-path] Migrate a configuration to a new version.
569+
configtest|t <config-path> Tests webpack configuration against validation errors.
570+
plugin|p [output-path] Scaffold a plugin.
570571
571572
To see list of all supported commands and options run 'webpack --help=verbose'.
572573

packages/configtest/package.json

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "@webpack-cli/configtest",
3+
"version": "1.0.0",
4+
"description": "Tests webpack configuration against validation errors.",
5+
"main": "lib/index.js",
6+
"types": "lib/index.d.ts",
7+
"license": "MIT",
8+
"publishConfig": {
9+
"access": "public"
10+
},
11+
"files": [
12+
"lib"
13+
],
14+
"peerDependencies": {
15+
"webpack": "4.x.x || 5.x.x",
16+
"webpack-cli": "4.x.x"
17+
}
18+
}

packages/configtest/src/index.ts

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import webpack from 'webpack';
2+
3+
class ConfigTestCommand {
4+
async apply(cli): Promise<void> {
5+
const { logger } = cli;
6+
7+
await cli.makeCommand(
8+
{
9+
name: 'configtest <config-path>',
10+
alias: 't',
11+
description: 'Tests webpack configuration against validation errors.',
12+
usage: '<config-path>',
13+
pkg: '@webpack-cli/configtest',
14+
},
15+
[],
16+
async (configPath: string): Promise<void> => {
17+
const config = await cli.resolveConfig({ config: [configPath] });
18+
19+
try {
20+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
21+
const error: any = webpack.validate(config.options);
22+
23+
// TODO remove this after drop webpack@4
24+
if (error && error.length > 0) {
25+
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
26+
// @ts-ignore
27+
throw new webpack.WebpackOptionsValidationError(error);
28+
}
29+
} catch (error) {
30+
const isValidationError = (error) => {
31+
// https://github.com/webpack/webpack/blob/master/lib/index.js#L267
32+
// https://github.com/webpack/webpack/blob/v4.44.2/lib/webpack.js#L90
33+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
34+
const ValidationError = (webpack.ValidationError || webpack.WebpackOptionsValidationError) as any;
35+
36+
return error instanceof ValidationError;
37+
};
38+
39+
if (isValidationError(error)) {
40+
logger.error(error.message);
41+
} else {
42+
logger.error(error);
43+
}
44+
45+
process.exit(2);
46+
}
47+
48+
logger.success('There are no validation errors in the given webpack configuration.');
49+
},
50+
);
51+
}
52+
}
53+
54+
export default ConfigTestCommand;

packages/configtest/tsconfig.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "./lib",
5+
"rootDir": "./src"
6+
},
7+
"include": ["./src"]
8+
}

packages/webpack-cli/README.md

+10-9
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,16 @@ npx webpack-cli --help verbose
6363
### Available Commands
6464

6565
```
66-
bundle | b Run webpack
67-
help | h Display help for commands and options
68-
version | v Output version number of the 'webpack', 'webpack-cli' and other related packages
69-
init | c Initialize a new webpack configuration
70-
migrate | m Migrate a configuration to a new version
71-
loader | l Scaffold a loader repository
72-
plugin | p Scaffold a plugin repository
73-
info | i Outputs information about your system and dependencies
74-
serve | s Run the webpack Dev Server
66+
bundle | b Run webpack
67+
help | h Display help for commands and options
68+
version | v Output version number of the 'webpack', 'webpack-cli' and other related packages
69+
init | c Initialize a new webpack configuration
70+
migrate | m Migrate a configuration to a new version
71+
loader | l Scaffold a loader repository
72+
plugin | p Scaffold a plugin repository
73+
info | i Outputs information about your system and dependencies
74+
serve | s Run the webpack Dev Server
75+
configtest | t Tests webpack configuration against validation errors.
7576
```
7677

7778
### webpack 4

packages/webpack-cli/lib/webpack-cli.js

+5
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,11 @@ class WebpackCLI {
279279
alias: 'm',
280280
pkg: '@webpack-cli/migrate',
281281
},
282+
{
283+
name: 'configtest',
284+
alias: 't',
285+
pkg: '@webpack-cli/configtest',
286+
},
282287
];
283288

284289
const knownCommands = [bundleCommandOptions, versionCommandOptions, helpCommandOptions, ...externalBuiltInCommandsInfo];

packages/webpack-cli/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
"@webpack-cli/migrate": {
5555
"optional": true
5656
},
57+
"@webpack-cli/configtest": {
58+
"optional": true
59+
},
5760
"webpack-bundle-analyzer": {
5861
"optional": true
5962
},

test/configtest/configtest.test.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
'use strict';
2+
3+
const { run } = require('../utils/test-utils');
4+
5+
describe('basic info usage', () => {
6+
it('should validate webpack config successfully', () => {
7+
const { exitCode, stderr, stdout } = run(__dirname, ['configtest', './webpack.config.js'], false);
8+
9+
expect(exitCode).toBe(0);
10+
expect(stderr).toBeFalsy();
11+
expect(stdout).toContain('There are no validation errors in the given webpack configuration.');
12+
});
13+
14+
it('should throw validation error', () => {
15+
const { exitCode, stderr, stdout } = run(__dirname, ['configtest', './error.config.js'], false);
16+
17+
expect(exitCode).toBe(2);
18+
expect(stderr).toContain('Invalid configuration object.');
19+
expect(stderr).toContain('configuration.mode should be one of these:');
20+
expect(stdout).toBeFalsy();
21+
});
22+
23+
it('should throw syntax error', () => {
24+
const { exitCode, stderr, stdout } = run(__dirname, ['configtest', './syntax-error.config.js'], false);
25+
26+
expect(exitCode).toBe(2);
27+
expect(stderr).toContain(`SyntaxError: Unexpected token ';'`);
28+
expect(stdout).toBeFalsy();
29+
});
30+
31+
it(`should validate the config with alias 't'`, () => {
32+
const { exitCode, stderr, stdout } = run(__dirname, ['t', './error.config.js'], false);
33+
34+
expect(exitCode).toBe(2);
35+
expect(stderr).toContain('Invalid configuration object.');
36+
expect(stderr).toContain('configuration.mode should be one of these:');
37+
expect(stdout).toBeFalsy();
38+
});
39+
40+
it('should throw error if configuration does not exist', () => {
41+
const { exitCode, stderr, stdout } = run(__dirname, ['configtest', './a.js'], false);
42+
43+
expect(exitCode).toBe(2);
44+
expect(stderr).toContain(`The specified config file doesn't exist`);
45+
expect(stdout).toBeFalsy();
46+
});
47+
48+
it('should throw error if no configuration was provided', () => {
49+
const { exitCode, stderr, stdout } = run(__dirname, ['configtest'], false);
50+
51+
expect(exitCode).toBe(2);
52+
expect(stderr).toContain(`error: missing required argument 'config-path'`);
53+
expect(stdout).toBeFalsy();
54+
});
55+
});

test/configtest/error.config.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
mode: 'dev', // error
3+
target: 'node',
4+
stats: 'normal',
5+
};

test/configtest/src/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('configtest command');
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
name: 'config-error',
3+
mode: 'development',
4+
target: 'node'; //SyntaxError: Unexpected token ';'
5+
};

test/configtest/webpack.config.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
mode: 'development',
3+
target: 'node',
4+
stats: 'verbose',
5+
};

test/help/help.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ describe('help', () => {
2828
expect(stdout.match(/loader\|l/g)).toHaveLength(1);
2929
expect(stdout.match(/migrate\|m/g)).toHaveLength(1);
3030
expect(stdout.match(/plugin\|p/g)).toHaveLength(1);
31+
expect(stdout.match(/configtest\|t/g)).toHaveLength(1);
3132
expect(stdout).toContain("To see list of all supported commands and options run 'webpack --help=verbose'.");
3233
expect(stdout).toContain('CLI documentation: https://webpack.js.org/api/cli/.');
3334
// TODO buggy on windows

tsconfig.json

+21-6
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,26 @@
2020
"declaration": true
2121
},
2222
"references": [
23-
{ "path": "packages/generators" },
24-
{ "path": "packages/info" },
25-
{ "path": "packages/init" },
26-
{ "path": "packages/migrate" },
27-
{ "path": "packages/serve" },
28-
{ "path": "packages/utils" }
23+
{
24+
"path": "packages/generators"
25+
},
26+
{
27+
"path": "packages/info"
28+
},
29+
{
30+
"path": "packages/init"
31+
},
32+
{
33+
"path": "packages/migrate"
34+
},
35+
{
36+
"path": "packages/serve"
37+
},
38+
{
39+
"path": "packages/utils"
40+
},
41+
{
42+
"path": "packages/configtest"
43+
}
2944
]
3045
}

0 commit comments

Comments
 (0)