Skip to content

Commit

Permalink
feat: new configtest command (#2303)
Browse files Browse the repository at this point in the history
  • Loading branch information
snitin315 committed Jan 6, 2021
1 parent 73d3fec commit eb7b189
Show file tree
Hide file tree
Showing 16 changed files with 197 additions and 18 deletions.
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> Tests webpack configuration against validation errors.
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": "Tests webpack configuration against validation errors.",
"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"
}
}
54 changes: 54 additions & 0 deletions packages/configtest/src/index.ts
@@ -0,0 +1,54 @@
import webpack from 'webpack';

class ConfigTestCommand {
async apply(cli): Promise<void> {
const { logger } = cli;

await cli.makeCommand(
{
name: 'configtest <config-path>',
alias: 't',
description: 'Tests webpack configuration against validation errors.',
usage: '<config-path>',
pkg: '@webpack-cli/configtest',
},
[],
async (configPath: string): Promise<void> => {
const config = await cli.resolveConfig({ config: [configPath] });

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

// TODO remove this after drop webpack@4
if (error && error.length > 0) {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
throw new webpack.WebpackOptionsValidationError(error);
}
} catch (error) {
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
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const ValidationError = (webpack.ValidationError || webpack.WebpackOptionsValidationError) as any;

return error instanceof ValidationError;
};

if (isValidationError(error)) {
logger.error(error.message);
} else {
logger.error(error);
}

process.exit(2);
}

logger.success('There are no validation errors in the given webpack configuration.');
},
);
}
}

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 Tests webpack configuration against validation errors.
```

### 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 validation 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',
};
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"
}
]
}

0 comments on commit eb7b189

Please sign in to comment.