Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement new configtest command #2303

Merged
merged 13 commits into from Jan 6, 2021
1 change: 1 addition & 0 deletions .eslintignore
Expand Up @@ -10,3 +10,4 @@ test/typescript/webpack.config.ts
test/config/error-commonjs/syntax-error.js
test/config/error-mjs/syntax-error.mjs
test/config/error-array/webpack.config.js
test/configtest/syntax-error.config.js
1 change: 1 addition & 0 deletions .prettierignore
Expand Up @@ -9,3 +9,4 @@ test/config/error-mjs/syntax-error.mjs
packages/webpack-cli/__tests__/test-assets/.yo-rc.json
test/build-errors/stats.json
packages/**/lib
test/configtest/syntax-error.config.js
7 changes: 4 additions & 3 deletions OPTIONS.md
Expand Up @@ -549,7 +549,7 @@ Options:
--watch-options-ignored-reset Clear all items provided in configuration. Ignore some files from watching (glob pattern or regexp).
--watch-options-poll <value> `number`: use polling with specified interval. `true`: use polling.
--watch-options-stdin Stop watching when stdin stream has ended.
--no-watch-options-stdin Negative 'watch-options-stdin' option.
--no-watch-options-stdin Do not stop watching when stdin stream has ended.

Global options:
--color Enable colors on console.
Expand All @@ -559,14 +559,15 @@ Global options:

Commands:
bundle|b [options] Run webpack (default command, can be omitted).
help|h Display help for commands and options.
version|v Output the version number of 'webpack', 'webpack-cli' and 'webpack-dev-server' and commands.
help|h Display help for commands and options.
serve|s [options] Run the webpack dev server.
info|i [options] Outputs information about your system.
init|c [options] [scaffold...] Initialize a new webpack configuration.
loader|l [output-path] Scaffold a loader.
plugin|p [output-path] Scaffold a plugin.
migrate|m <config-path> [new-config-path] Migrate a configuration to a new version.
configtest|t <config-path> Test your webpack configuration against validation errors.
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
plugin|p [output-path] Scaffold a plugin.

To see list of all supported commands and options run 'webpack --help=verbose'.

Expand Down
18 changes: 18 additions & 0 deletions packages/configtest/package.json
@@ -0,0 +1,18 @@
{
"name": "@webpack-cli/configtest",
"version": "1.0.0",
"description": "Test your webpack configuration against validation errors.",
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
"main": "lib/index.js",
"types": "lib/index.d.ts",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"files": [
"lib"
],
"peerDependencies": {
"webpack": "4.x.x || 5.x.x",
"webpack-cli": "4.x.x"
}
}
50 changes: 50 additions & 0 deletions packages/configtest/src/index.ts
@@ -0,0 +1,50 @@
class ConfigTestCommand {
async apply(cli): Promise<void> {
const { logger } = cli;

await cli.makeCommand(
{
name: 'configtest <config-path>',
alias: 't',
description: 'Test your webpack configuration against validation errors.',
usage: '[configs]',
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
pkg: '@webpack-cli/configtest',
},
[],
async (configPath: string): Promise<void> => {
//eslint-disable-next-line @typescript-eslint/no-var-requires
const { validate, version, ValidationError, WebpackOptionsValidationError } = require('webpack');

const isWebpack5: boolean = version.startsWith('5');
const { options } = await cli.resolveConfig({ config: [configPath] });

const isValidationError = (error): boolean => {
// https://github.com/webpack/webpack/blob/master/lib/index.js#L267
// https://github.com/webpack/webpack/blob/v4.44.2/lib/webpack.js#L90
//eslint-disable-next-line @typescript-eslint/no-explicit-any
const webpackValidationError: any = ValidationError || WebpackOptionsValidationError;

return error instanceof webpackValidationError;
};

//eslint-disable-next-line @typescript-eslint/no-explicit-any
const error: any = validate(options);

if (error && error.length) {
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
if (isWebpack5) {
logger.error(isValidationError(error) ? error.message : error);
} else {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
logger.error(new WebpackOptionsValidationError(error));
}
process.exit(2);
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
}

logger.success('There are no errors in the given webpack configuration.');
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
},
);
}
}

export default ConfigTestCommand;
8 changes: 8 additions & 0 deletions packages/configtest/tsconfig.json
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./lib",
"rootDir": "./src"
},
"include": ["./src"]
}
19 changes: 10 additions & 9 deletions packages/webpack-cli/README.md
Expand Up @@ -63,15 +63,16 @@ npx webpack-cli --help verbose
### Available Commands

```
bundle | b Run webpack
help | h Display help for commands and options
version | v Output version number of the 'webpack', 'webpack-cli' and other related packages
init | c Initialize a new webpack configuration
migrate | m Migrate a configuration to a new version
loader | l Scaffold a loader repository
plugin | p Scaffold a plugin repository
info | i Outputs information about your system and dependencies
serve | s Run the webpack Dev Server
bundle | b Run webpack
help | h Display help for commands and options
version | v Output version number of the 'webpack', 'webpack-cli' and other related packages
init | c Initialize a new webpack configuration
migrate | m Migrate a configuration to a new version
loader | l Scaffold a loader repository
plugin | p Scaffold a plugin repository
info | i Outputs information about your system and dependencies
serve | s Run the webpack Dev Server
configtest | t Test your webpack configuration against validation errors.
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
```

### webpack 4
Expand Down
5 changes: 5 additions & 0 deletions packages/webpack-cli/lib/webpack-cli.js
Expand Up @@ -279,6 +279,11 @@ class WebpackCLI {
alias: 'm',
pkg: '@webpack-cli/migrate',
},
{
name: 'configtest',
alias: 't',
pkg: '@webpack-cli/configtest',
},
];

const knownCommands = [bundleCommandOptions, versionCommandOptions, helpCommandOptions, ...externalBuiltInCommandsInfo];
Expand Down
3 changes: 3 additions & 0 deletions packages/webpack-cli/package.json
Expand Up @@ -54,6 +54,9 @@
"@webpack-cli/migrate": {
"optional": true
},
"@webpack-cli/configtest": {
"optional": true
},
"webpack-bundle-analyzer": {
"optional": true
},
Expand Down
55 changes: 55 additions & 0 deletions test/configtest/configtest.test.js
@@ -0,0 +1,55 @@
'use strict';

const { run } = require('../utils/test-utils');

describe('basic info usage', () => {
it('should validate webpack config successfully', () => {
const { exitCode, stderr, stdout } = run(__dirname, ['configtest', './webpack.config.js'], false);

expect(exitCode).toBe(0);
expect(stderr).toBeFalsy();
expect(stdout).toContain('There are no errors in the given webpack configuration.');
});

it('should throw validation error', () => {
const { exitCode, stderr, stdout } = run(__dirname, ['configtest', './error.config.js'], false);

expect(exitCode).toBe(2);
expect(stderr).toContain('Invalid configuration object.');
expect(stderr).toContain('configuration.mode should be one of these:');
expect(stdout).toBeFalsy();
});

it('should throw syntax error', () => {
const { exitCode, stderr, stdout } = run(__dirname, ['configtest', './syntax-error.config.js'], false);

expect(exitCode).toBe(2);
expect(stderr).toContain(`SyntaxError: Unexpected token ';'`);
expect(stdout).toBeFalsy();
});

it(`should validate the config with alias 't'`, () => {
const { exitCode, stderr, stdout } = run(__dirname, ['t', './error.config.js'], false);

expect(exitCode).toBe(2);
expect(stderr).toContain('Invalid configuration object.');
expect(stderr).toContain('configuration.mode should be one of these:');
expect(stdout).toBeFalsy();
});

it('should throw error if configuration does not exist', () => {
const { exitCode, stderr, stdout } = run(__dirname, ['configtest', './a.js'], false);

expect(exitCode).toBe(2);
expect(stderr).toContain(`The specified config file doesn't exist`);
expect(stdout).toBeFalsy();
});

it('should throw error if no configuration was provided', () => {
const { exitCode, stderr, stdout } = run(__dirname, ['configtest'], false);

expect(exitCode).toBe(2);
expect(stderr).toContain(`error: missing required argument 'config-path'`);
expect(stdout).toBeFalsy();
});
});
5 changes: 5 additions & 0 deletions test/configtest/error.config.js
@@ -0,0 +1,5 @@
module.exports = {
mode: 'dev', // error
target: 'node',
stats: 'normal',
};
1 change: 1 addition & 0 deletions test/configtest/src/index.js
@@ -0,0 +1 @@
console.log('configtest command');
5 changes: 5 additions & 0 deletions test/configtest/syntax-error.config.js
@@ -0,0 +1,5 @@
module.exports = {
name: 'config-error',
mode: 'development',
target: 'node'; //SyntaxError: Unexpected token ';'
};
5 changes: 5 additions & 0 deletions test/configtest/webpack.config.js
@@ -0,0 +1,5 @@
module.exports = {
mode: 'development',
target: 'node',
stats: 'verbose',
};
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions test/help/help.test.js
Expand Up @@ -28,6 +28,7 @@ describe('help', () => {
expect(stdout.match(/loader\|l/g)).toHaveLength(1);
expect(stdout.match(/migrate\|m/g)).toHaveLength(1);
expect(stdout.match(/plugin\|p/g)).toHaveLength(1);
expect(stdout.match(/configtest\|t/g)).toHaveLength(1);
expect(stdout).toContain("To see list of all supported commands and options run 'webpack --help=verbose'.");
expect(stdout).toContain('CLI documentation: https://webpack.js.org/api/cli/.');
// TODO buggy on windows
Expand Down
27 changes: 21 additions & 6 deletions tsconfig.json
Expand Up @@ -20,11 +20,26 @@
"declaration": true
},
"references": [
{ "path": "packages/generators" },
{ "path": "packages/info" },
{ "path": "packages/init" },
{ "path": "packages/migrate" },
{ "path": "packages/serve" },
{ "path": "packages/utils" }
{
"path": "packages/generators"
},
{
"path": "packages/info"
},
{
"path": "packages/init"
},
{
"path": "packages/migrate"
},
{
"path": "packages/serve"
},
{
"path": "packages/utils"
},
{
"path": "packages/configtest"
}
]
}