├── .npmignore
├── test
├── fixtures
│ ├── reporters
│ │ ├── stylish
│ │ │ ├── big
│ │ │ │ ├── entry.js
│ │ │ │ └── webpack.config.js
│ │ │ ├── multi
│ │ │ │ ├── client.js
│ │ │ │ ├── server.js
│ │ │ │ └── webpack.config.js
│ │ │ ├── nonstandard
│ │ │ │ ├── test.scss
│ │ │ │ ├── entry.js
│ │ │ │ ├── webpack.config.js
│ │ │ │ ├── webpack.bad-rule.config.js
│ │ │ │ ├── .stylelintrc
│ │ │ │ └── bad-rule.stylelintrc
│ │ │ ├── loaders
│ │ │ │ ├── image.jpg
│ │ │ │ ├── index.html
│ │ │ │ ├── entry.js
│ │ │ │ └── webpack.config.js
│ │ │ ├── problems
│ │ │ │ ├── image.jpg
│ │ │ │ ├── entry-problems.js
│ │ │ │ └── stylish-problems.js
│ │ │ ├── basic
│ │ │ │ ├── entry.js
│ │ │ │ ├── webpack.no-named.config.js
│ │ │ │ └── webpack.config.js
│ │ │ ├── stylish.js
│ │ │ └── stylish-multi.js
│ │ └── json
│ │ │ ├── problems
│ │ │ ├── image.jpg
│ │ │ ├── entry-problems.js
│ │ │ └── problems.js
│ │ │ ├── json.js
│ │ │ └── json-multi.js
│ ├── common
│ │ ├── entry-a.js
│ │ ├── entry-b.js
│ │ ├── entry-c.js
│ │ ├── loader.js
│ │ ├── loader-post.js
│ │ ├── loader-pre.js
│ │ ├── webpack.config.js
│ │ └── test-reporter.js
│ ├── flags
│ │ ├── resolve
│ │ │ ├── dependency.custom
│ │ │ ├── aliased
│ │ │ │ └── dependency.js
│ │ │ ├── entry.js
│ │ │ ├── entry-extensions.js
│ │ │ ├── entry-loader-alias.js
│ │ │ ├── resolve-extensions.js
│ │ │ ├── resolve-alias.js
│ │ │ └── resolve-loader-alias.js
│ │ ├── config
│ │ │ ├── argv.config.js
│ │ │ ├── src
│ │ │ │ └── index.js
│ │ │ ├── config-not-found.js
│ │ │ └── config.js
│ │ ├── prefetch
│ │ │ ├── dependency.js
│ │ │ ├── entry.js
│ │ │ └── prefetch.js
│ │ ├── define
│ │ │ ├── entry.js
│ │ │ └── define.js
│ │ ├── output
│ │ │ ├── output-entry.js
│ │ │ ├── output-path.js
│ │ │ ├── output-pathinfo.js
│ │ │ ├── output-library.js
│ │ │ ├── output.js
│ │ │ ├── output-filename.js
│ │ │ ├── output-library-target.js
│ │ │ ├── output-public-path.js
│ │ │ ├── output-jsonp-function.js
│ │ │ ├── output-chunk-filename.js
│ │ │ └── output-source-map-filename.js
│ │ ├── bail
│ │ │ ├── entry.js
│ │ │ └── bail.js
│ │ ├── entry
│ │ │ ├── single.js
│ │ │ └── multi.js
│ │ ├── hot
│ │ │ └── hot.js
│ │ ├── cache
│ │ │ └── cache.js
│ │ ├── debug
│ │ │ └── debug.js
│ │ ├── run-mode
│ │ │ ├── run-dev.js
│ │ │ └── run-prod.js
│ │ ├── mode
│ │ │ ├── dev.js
│ │ │ └── prod.js
│ │ ├── target
│ │ │ └── target.js
│ │ ├── watch
│ │ │ ├── watch-poll.js
│ │ │ ├── watch-stdin.js
│ │ │ ├── single-flag.js
│ │ │ ├── watch-aggregate-timeout.js
│ │ │ ├── single-config.js
│ │ │ ├── multi-flag.js
│ │ │ └── multi-config.js
│ │ ├── devtool
│ │ │ └── devtool.js
│ │ ├── optimize
│ │ │ ├── optimize-minimize.js
│ │ │ ├── optimize-min-chunk-size.js
│ │ │ └── optimize-max-chunks.js
│ │ ├── plugin
│ │ │ └── plugin.js
│ │ ├── config-name
│ │ │ ├── single-array.js
│ │ │ ├── multi-found.js
│ │ │ ├── single-object.js
│ │ │ ├── multi-missing.js
│ │ │ └── multi-duplicate.js
│ │ ├── profile
│ │ │ └── profile.js
│ │ ├── progress
│ │ │ └── progress.js
│ │ ├── records
│ │ │ ├── records-path.js
│ │ │ └── records-input-output.js
│ │ ├── context
│ │ │ └── context.js
│ │ ├── provide
│ │ │ └── provide.js
│ │ ├── module-bind
│ │ │ ├── bind.js
│ │ │ ├── bind-pre.js
│ │ │ ├── bind-post.js
│ │ │ └── bind-all.js
│ │ └── reporter
│ │ │ ├── basic.js
│ │ │ └── basic-multi.js
│ ├── bail
│ │ ├── entry.js
│ │ └── webpack.config.js
│ ├── zero-config
│ │ └── src
│ │ │ └── index.js
│ ├── bad-config
│ │ └── webpack.config.js
│ ├── progress
│ │ ├── webpack.config.js
│ │ └── entry.js
│ └── commands
│ │ └── TestCommand.js
├── .eslintrc
├── tests
│ ├── commands
│ │ ├── __snapshots__
│ │ │ ├── command.js.snap
│ │ │ ├── teach.js.snap
│ │ │ └── help.js.snap
│ │ ├── command.js
│ │ ├── help.js
│ │ └── teach.js
│ ├── flags
│ │ ├── __snapshots__
│ │ │ ├── config.js.snap
│ │ │ ├── bail.js.snap
│ │ │ ├── progress.js.snap
│ │ │ ├── profile.js.snap
│ │ │ ├── context.js.snap
│ │ │ ├── cache.js.snap
│ │ │ ├── config-name.js.snap
│ │ │ ├── target.js.snap
│ │ │ ├── hot.js.snap
│ │ │ ├── debug.js.snap
│ │ │ ├── provide.js.snap
│ │ │ ├── define.js.snap
│ │ │ ├── devtool.js.snap
│ │ │ ├── prefetch.js.snap
│ │ │ ├── plugin.js.snap
│ │ │ ├── mode.js.snap
│ │ │ ├── run-mode.js.snap
│ │ │ ├── records.js.snap
│ │ │ ├── watch.js.snap
│ │ │ ├── entry.js.snap
│ │ │ ├── optimize.js.snap
│ │ │ ├── resolve.js.snap
│ │ │ └── module-bind.js.snap
│ │ ├── progress.js
│ │ ├── config.js
│ │ ├── hot.js
│ │ ├── cache.js
│ │ ├── debug.js
│ │ ├── context.js
│ │ ├── plugin.js
│ │ ├── provide.js
│ │ ├── target.js
│ │ ├── prefetch.js
│ │ ├── define.js
│ │ ├── profile.js
│ │ ├── bail.js
│ │ ├── mode.js
│ │ ├── optimize.js
│ │ ├── records.js
│ │ ├── resolve.js
│ │ ├── devtool.js
│ │ ├── reporter.js
│ │ ├── config-name.js
│ │ ├── output.js
│ │ ├── run-mode.js
│ │ ├── watch.js
│ │ ├── module-bind.js
│ │ └── entry.js
│ ├── progress.js
│ ├── config.js
│ ├── flags.js
│ ├── __snapshots__
│ │ └── config.js.snap
│ ├── cli.js
│ └── reporters.js
├── test.js
├── snapshot.js
└── util.js
├── .eslintignore
├── .gitattributes
├── .nsprc
├── lib
├── WebpackCommandError.js
├── commands
│ ├── defaults.json
│ ├── Command.js
│ ├── index.js
│ ├── HelpCommand.js
│ └── TeachCommand.js
├── global.js
├── flags
│ ├── module.js
│ ├── config.js
│ ├── resolver.js
│ ├── optimization.js
│ ├── output.js
│ ├── index.js
│ ├── general.js
│ └── advanced.js
├── reporters
│ ├── JsonReporter.js
│ ├── Reporter.js
│ ├── BasicReporter.js
│ └── StylishReporter.js
├── index.js
├── entry.js
├── progress.js
└── config.js
├── .prettierrc
├── assets
└── did-you-mean.png
├── codecov.yml
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── SUPPORT.md
│ ├── FEATURE.md
│ ├── DOCS.md
│ ├── MODIFICATION.md
│ └── BUG.md
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── docs
├── HelpCommand.md
└── TeachCommand.md
├── commitlint.config.js
├── LICENSE
├── CONTRIBUTING.md
├── package.json
└── .circleci
└── config.yml
/.npmignore:
--------------------------------------------------------------------------------
1 | lib/client
2 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/big/entry.js:
--------------------------------------------------------------------------------
1 | require('./big');
2 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/multi/client.js:
--------------------------------------------------------------------------------
1 | require('chalk');
2 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /dist
3 | *.snap
4 | big.js
5 | main.js
6 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | package-lock.json -diff
2 | * text=auto
3 | bin/* eol=lf
4 |
--------------------------------------------------------------------------------
/.nsprc:
--------------------------------------------------------------------------------
1 | {
2 | "exceptions": ["https://nodesecurity.io/advisories/612"]
3 | }
4 |
--------------------------------------------------------------------------------
/test/fixtures/common/entry-a.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | name: 'entry-a',
3 | };
4 |
--------------------------------------------------------------------------------
/test/fixtures/common/entry-b.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | name: 'entry-b',
3 | };
4 |
--------------------------------------------------------------------------------
/test/fixtures/common/entry-c.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | name: 'entry-c',
3 | };
4 |
--------------------------------------------------------------------------------
/test/fixtures/common/loader.js:
--------------------------------------------------------------------------------
1 | module.exports = (source) => `loader: ${source}`;
2 |
--------------------------------------------------------------------------------
/test/fixtures/flags/resolve/dependency.custom:
--------------------------------------------------------------------------------
1 | module.exports = 'dependency-custom';
2 |
--------------------------------------------------------------------------------
/lib/WebpackCommandError.js:
--------------------------------------------------------------------------------
1 | module.exports = class WebpackCommandError extends Error {};
2 |
--------------------------------------------------------------------------------
/test/fixtures/bail/entry.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line
2 | require('batman-module.js');
3 |
--------------------------------------------------------------------------------
/test/fixtures/flags/resolve/aliased/dependency.js:
--------------------------------------------------------------------------------
1 | module.exports = 'aliased-dependency';
2 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/nonstandard/test.scss:
--------------------------------------------------------------------------------
1 | body {
2 | color: #FFF;
3 | }
4 |
--------------------------------------------------------------------------------
/test/fixtures/zero-config/src/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | name: 'src/index',
3 | };
4 |
--------------------------------------------------------------------------------
/test/fixtures/flags/config/argv.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | mode: 'development',
3 | };
4 |
--------------------------------------------------------------------------------
/test/fixtures/flags/config/src/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | name: 'src/index',
3 | };
4 |
--------------------------------------------------------------------------------
/lib/commands/defaults.json:
--------------------------------------------------------------------------------
1 | {
2 | "help": "./HelpCommand",
3 | "teach": "./TeachCommand"
4 | }
5 |
--------------------------------------------------------------------------------
/test/fixtures/common/loader-post.js:
--------------------------------------------------------------------------------
1 | module.exports = (source) => `${source}\nconst post = true;`;
2 |
--------------------------------------------------------------------------------
/test/fixtures/common/loader-pre.js:
--------------------------------------------------------------------------------
1 | module.exports = (source) => `${source}\nconst pre = true;`;
2 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/multi/server.js:
--------------------------------------------------------------------------------
1 | const { log } = console;
2 |
3 | log('server');
4 |
--------------------------------------------------------------------------------
/test/fixtures/flags/prefetch/dependency.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | name: 'prefetch-dependency',
3 | };
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "es5",
4 | "arrowParens": "always"
5 | }
6 |
--------------------------------------------------------------------------------
/assets/did-you-mean.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webpack-contrib/webpack-command/HEAD/assets/did-you-mean.png
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/nonstandard/entry.js:
--------------------------------------------------------------------------------
1 | require('file-loader!./test.scss'); // eslint-disable-line
2 |
--------------------------------------------------------------------------------
/test/fixtures/bad-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | mode: 'development',
3 | batman: 'i am',
4 | };
5 |
--------------------------------------------------------------------------------
/test/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "globals": {
3 | "fixture": true,
4 | "fixturePath": true,
5 | "resolve": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/test/fixtures/flags/define/entry.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | name: 'entry-a',
3 | result: DEFINE, // eslint-disable-line no-undef
4 | };
5 |
--------------------------------------------------------------------------------
/test/fixtures/flags/output/output-entry.js:
--------------------------------------------------------------------------------
1 | require('../../common/entry-a');
2 |
3 | module.exports = {
4 | name: 'output-entry',
5 | };
6 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/json/problems/image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webpack-contrib/webpack-command/HEAD/test/fixtures/reporters/json/problems/image.jpg
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/loaders/image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webpack-contrib/webpack-command/HEAD/test/fixtures/reporters/stylish/loaders/image.jpg
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/problems/image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webpack-contrib/webpack-command/HEAD/test/fixtures/reporters/stylish/problems/image.jpg
--------------------------------------------------------------------------------
/test/fixtures/flags/bail/entry.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/no-unresolved
2 | require('./missing');
3 |
4 | module.exports = {
5 | name: 'entry-bail',
6 | };
7 |
--------------------------------------------------------------------------------
/test/tests/commands/__snapshots__/command.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`help command > should display help #0 1`] = `""`;
4 |
--------------------------------------------------------------------------------
/test/fixtures/flags/prefetch/entry.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/no-unresolved
2 | require('./dependency');
3 |
4 | module.exports = {
5 | name: 'entry-bail',
6 | };
7 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/loaders/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= htmlWebpackPlugin.options.title %>
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/test/fixtures/flags/resolve/entry.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line no-unused-vars, import/no-unresolved
2 | const dependency = require('aliased/dependency');
3 |
4 | module.exports = 'resolve-entry';
5 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | branch: master
3 | coverage:
4 | precision: 2
5 | round: down
6 | range: 70...100
7 | status:
8 | project: 'no'
9 | patch: 'yes'
10 | comment: 'off'
11 |
--------------------------------------------------------------------------------
/test/fixtures/flags/resolve/entry-extensions.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line no-unused-vars, import/no-unresolved
2 | const dependency = require('./dependency');
3 |
4 | module.exports = 'resolve-entry';
5 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/basic/entry.js:
--------------------------------------------------------------------------------
1 | require('chalk');
2 |
3 | // warning
4 | // console.log(require);
5 |
6 | // error
7 | // if (!window) { require('test'); }
8 | // require('./image.jpg');
9 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/loaders/entry.js:
--------------------------------------------------------------------------------
1 | require('chalk');
2 |
3 | // warning
4 | // console.log(require);
5 |
6 | // error
7 | // if (!window) { require('test'); }
8 |
9 | require('./image.jpg');
10 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/json/problems/entry-problems.js:
--------------------------------------------------------------------------------
1 | // warning
2 | console.log(require); // eslint-disable-line
3 |
4 | // error
5 | if (!window) { require('test'); } // eslint-disable-line
6 |
7 | require('./image.jpg');
8 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/problems/entry-problems.js:
--------------------------------------------------------------------------------
1 | // warning
2 | console.log(require); // eslint-disable-line
3 |
4 | // error
5 | if (!window) { require('test'); } // eslint-disable-line
6 |
7 | require('./image.jpg');
8 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # These are the default owners for everything in
2 | # webpack-contrib
3 | @webpack-contrib/org-maintainers
4 |
5 | # Add repository specific users / groups
6 | # below here for libs that are not maintained by the org.
7 |
--------------------------------------------------------------------------------
/test/fixtures/flags/config/config-not-found.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const configPath = resolve(__dirname, '../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--config', configPath],
7 |
8 | group: 'config',
9 | };
10 |
--------------------------------------------------------------------------------
/test/fixtures/flags/entry/single.js:
--------------------------------------------------------------------------------
1 | const config = require('../../common/webpack.config');
2 |
3 | module.exports = {
4 | arguments: ['--entry', './test/fixtures/common/entry-a.js'],
5 |
6 | config: Object.assign({}, config),
7 |
8 | group: 'general',
9 | };
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | insert_final_newline = false
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/test/fixtures/progress/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const { NamedModulesPlugin } = require('webpack');
4 |
5 | module.exports = {
6 | entry: resolve(__dirname, './entry.js'),
7 | mode: 'development',
8 | plugins: [new NamedModulesPlugin()],
9 | };
10 |
--------------------------------------------------------------------------------
/test/fixtures/common/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const { NamedModulesPlugin } = require('webpack');
4 |
5 | module.exports = {
6 | mode: 'development',
7 | plugins: [new NamedModulesPlugin()],
8 | reporter: resolve(__dirname, 'test-reporter.js'),
9 | };
10 |
--------------------------------------------------------------------------------
/test/fixtures/commands/TestCommand.js:
--------------------------------------------------------------------------------
1 | const Command = require('../../../lib/commands/Command');
2 |
3 | module.exports = class HelpCommand extends Command {
4 | help() {
5 | return '';
6 | }
7 |
8 | // eslint-disable-next-line consistent-return
9 | run() {
10 | return true;
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/test/fixtures/flags/output/output-path.js:
--------------------------------------------------------------------------------
1 | const config = require('../../common/webpack.config');
2 |
3 | module.exports = {
4 | arguments: ['--output-path', './dist/.output'],
5 |
6 | config: Object.assign({}, config, {
7 | entry: resolve(__dirname, './output-entry.js'),
8 | }),
9 |
10 | group: 'output',
11 | };
12 |
--------------------------------------------------------------------------------
/test/fixtures/flags/bail/bail.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--bail'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './entry.js'),
10 | }),
11 |
12 | group: 'advanced',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/hot/hot.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--hot'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'advanced',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/resolve/entry-loader-alias.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const dependencyPath = resolve(__dirname, '../../common/entry-a.js');
4 | // eslint-disable-next-line no-unused-vars, import/no-dynamic-require
5 | const dependency = require(`aliased!${dependencyPath}`);
6 |
7 | module.exports = 'resolve-loader-alias-entry';
8 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | plugins: ['prettier'],
4 | extends: ['@webpack-contrib/eslint-config-webpack'],
5 | rules: {
6 | 'class-methods-use-this': 'off',
7 | 'prettier/prettier': [
8 | 'error',
9 | { singleQuote: true, trailingComma: 'es5', arrowParens: 'always' },
10 | ],
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/test/fixtures/flags/cache/cache.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--cache'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'advanced',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/debug/debug.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--debug'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'general',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/bail/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const { NamedModulesPlugin } = require('webpack');
4 |
5 | module.exports = {
6 | bail: true,
7 | entry: resolve(__dirname, 'entry.js'),
8 | mode: 'development',
9 | plugins: [new NamedModulesPlugin()],
10 | reporter: resolve(__dirname, 'test-reporter.js'),
11 | };
12 |
--------------------------------------------------------------------------------
/test/fixtures/flags/run-mode/run-dev.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--run-dev'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'general',
13 | };
14 |
--------------------------------------------------------------------------------
/lib/global.js:
--------------------------------------------------------------------------------
1 | /* istanbul ignore next */
2 | /* eslint-disable global-require, no-console, import/no-extraneous-dependencies */
3 |
4 | module.exports = {
5 | register() {
6 | require('v8-compile-cache');
7 | require('loud-rejection/register');
8 |
9 | if (!Object.values) {
10 | require('object.values').shim();
11 | }
12 | },
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/entry/multi.js:
--------------------------------------------------------------------------------
1 | const config = require('../../common/webpack.config');
2 |
3 | module.exports = {
4 | arguments: [
5 | '--entry',
6 | './test/fixtures/common/entry-a.js',
7 | '--entry',
8 | './test/fixtures/common/entry-b.js',
9 | ],
10 |
11 | config: Object.assign({}, config),
12 |
13 | group: 'general',
14 | };
15 |
--------------------------------------------------------------------------------
/test/fixtures/flags/mode/dev.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--mode', 'development'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'config',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/mode/prod.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--mode', 'production'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'config',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/run-mode/run-prod.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--run-prod'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'general',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/target/target.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--target', 'node'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'advanced',
13 | };
14 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/config.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --config > should build #0 1`] = `
4 | "Version: webpack 4.14.0
5 | Asset Size Chunks Chunk Names
6 | main.js 3.81 KiB main [emitted] main
7 | Entrypoint main = main.js
8 | [./src/index.js] 43 bytes {main} [built]"
9 | `;
10 |
--------------------------------------------------------------------------------
/test/fixtures/flags/output/output-pathinfo.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--output-pathinfo'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './output-entry.js'),
10 | }),
11 |
12 | group: 'output',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/watch/watch-poll.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--watch-poll', 1000],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'advanced',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/watch/watch-stdin.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--watch-stdin'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'advanced',
13 | };
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .nyc_output
3 | node_modules
4 | coverage
5 | coverage.lcov
6 | npm-debug.log
7 | test/**/dist/*
8 | logs
9 | *.log
10 | npm-debug.log*
11 | .eslintcache
12 | /coverage
13 | /dist
14 | /local
15 | /reports
16 | /node_modules
17 | Thumbs.db
18 | .idea
19 | .vscode
20 | *.sublime-project
21 | *.sublime-workspace
22 | .nyc_output
23 | data/commands.json
24 |
--------------------------------------------------------------------------------
/test/fixtures/flags/devtool/devtool.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--devtool', 'cheap-source-map'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'general',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/output/output-library.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--output-library', '__output__'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './output-entry.js'),
10 | }),
11 |
12 | group: 'output',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/output/output.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--output', './dist/.output/bundle.js'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './output-entry.js'),
10 | }),
11 |
12 | group: 'output',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/optimize/optimize-minimize.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--optimize-minimize'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'optimization',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/plugin/plugin.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--plugin', 'uglifyjs-webpack-plugin'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'advanced',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/config-name/single-array.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | module.exports = {
4 | arguments: ['--config-name', 'single-object'],
5 |
6 | config: [
7 | {
8 | entry: resolve(__dirname, '../../common/entry-a.js'),
9 | mode: 'development',
10 | name: 'single-object',
11 | },
12 | ],
13 |
14 | group: 'config',
15 | };
16 |
--------------------------------------------------------------------------------
/test/fixtures/flags/output/output-filename.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--output-filename', 'output-[name].js'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './output-entry.js'),
10 | }),
11 |
12 | group: 'output',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/output/output-library-target.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--output-library-target', 'var'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './output-entry.js'),
10 | }),
11 |
12 | group: 'output',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/output/output-public-path.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--output-public-path', '/output-path/'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './output-entry.js'),
10 | }),
11 |
12 | group: 'output',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/resolve/resolve-extensions.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--resolve-extensions', '.custom'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, 'entry-extensions.js'),
10 | }),
11 |
12 | group: 'resolver',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/watch/single-flag.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--watch'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | name: 'single-flag',
11 | }),
12 |
13 | group: 'general',
14 | };
15 |
--------------------------------------------------------------------------------
/test/fixtures/flags/output/output-jsonp-function.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--output-jsonp-function', 'output-func'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './output-entry.js'),
10 | }),
11 |
12 | group: 'output',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/profile/profile.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--profile'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | inspect: 'stdout',
13 |
14 | group: 'advanced',
15 | };
16 |
--------------------------------------------------------------------------------
/test/fixtures/flags/progress/progress.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--progress'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | inspect: 'stdout',
13 |
14 | group: 'general',
15 | };
16 |
--------------------------------------------------------------------------------
/test/fixtures/flags/records/records-path.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--records-path', './dist/records.json'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'advanced',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/watch/watch-aggregate-timeout.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--watch-aggregate-timeout', 400],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'advanced',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/basic/webpack.no-named.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | // mode: 'development',x
5 | context: __dirname,
6 | devtool: 'source-map',
7 | entry: './entry.js',
8 | output: {
9 | filename: './output.js',
10 | path: path.join(__dirname, '/dist'),
11 | },
12 | plugins: [],
13 | stats: 'none',
14 | };
15 |
--------------------------------------------------------------------------------
/test/fixtures/flags/context/context.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | const context = resolve(__dirname, '../../common');
6 |
7 | module.exports = {
8 | arguments: ['--context', context],
9 |
10 | config: Object.assign({}, config, {
11 | entry: './entry-a.js',
12 | }),
13 |
14 | group: 'general',
15 | };
16 |
--------------------------------------------------------------------------------
/test/fixtures/flags/prefetch/prefetch.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--prefetch', './test/fixtures/flags/prefetch/dependency.js'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './entry.js'),
10 | }),
11 |
12 | group: 'advanced',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/optimize/optimize-min-chunk-size.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--optimize-min-chunk-size', '10'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'optimization',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/output/output-chunk-filename.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--output-chunk-filename', '[id].output-chunk.js'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './output-entry.js'),
10 | }),
11 |
12 | group: 'output',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/flags/provide/provide.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--provide.$', 'jquery', '--provide.jQuery', 'jquery'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | group: 'advanced',
13 | };
14 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/json/json.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: [],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | reporter: 'json',
11 | }),
12 |
13 | inspect: 'stdout',
14 |
15 | group: 'general',
16 | };
17 |
--------------------------------------------------------------------------------
/test/fixtures/flags/watch/single-config.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: [],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | name: 'single-config',
11 | watch: true,
12 | }),
13 |
14 | group: 'advanced',
15 | };
16 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/json/problems/problems.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: [],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './entry-problems.js'),
10 | reporter: 'json',
11 | }),
12 |
13 | inspect: 'stdout',
14 |
15 | group: 'general',
16 | };
17 |
--------------------------------------------------------------------------------
/test/fixtures/flags/config/config.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const configPath = resolve(__dirname, './argv.config.js');
4 | const reporterPath = resolve(__dirname, '../../common/test-reporter.js');
5 |
6 | module.exports = {
7 | arguments: [
8 | '--config',
9 | configPath,
10 | '--context',
11 | __dirname,
12 | '--reporter',
13 | reporterPath,
14 | ],
15 |
16 | group: 'config',
17 | };
18 |
--------------------------------------------------------------------------------
/test/fixtures/flags/output/output-source-map-filename.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--output-source-map-filename', 'output-[name].map'],
7 |
8 | config: Object.assign({}, config, {
9 | devtool: 'source-map',
10 | entry: resolve(__dirname, './output-entry.js'),
11 | }),
12 |
13 | group: 'output',
14 | };
15 |
--------------------------------------------------------------------------------
/test/fixtures/flags/resolve/resolve-alias.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | const aliasPath = resolve(__dirname, 'aliased');
6 |
7 | module.exports = {
8 | arguments: ['--resolve-alias.aliased', `${aliasPath}`],
9 |
10 | config: Object.assign({}, config, {
11 | entry: resolve(__dirname, 'entry.js'),
12 | }),
13 |
14 | group: 'resolver',
15 | };
16 |
--------------------------------------------------------------------------------
/test/fixtures/flags/watch/multi-flag.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | module.exports = {
4 | arguments: ['--watch'],
5 |
6 | config: [
7 | {
8 | entry: resolve(__dirname, '../../common/entry-a.js'),
9 | mode: 'development',
10 | },
11 | {
12 | entry: resolve(__dirname, '../../common/entry-b.js'),
13 | mode: 'development',
14 | },
15 | ],
16 |
17 | group: 'general',
18 | };
19 |
--------------------------------------------------------------------------------
/lib/commands/Command.js:
--------------------------------------------------------------------------------
1 | module.exports = class Command {
2 | constructor() {
3 | this.init = true;
4 | }
5 |
6 | // eslint-disable-next-line class-methods-use-this
7 | help() {
8 | return '';
9 | }
10 |
11 | run(/* cli */) {}
12 | };
13 |
14 | module.exports.CommandError = class CommandError extends Error {
15 | constructor(...args) {
16 | super(...args);
17 | this.name = 'CommandError';
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/test/fixtures/flags/module-bind/bind.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | const loaderPath = resolve(__dirname, '../../common/loader');
6 |
7 | module.exports = {
8 | arguments: ['--module-bind', `js=${loaderPath}`],
9 |
10 | config: Object.assign({}, config, {
11 | entry: resolve(__dirname, '../../common/entry-a.js'),
12 | }),
13 |
14 | group: 'module',
15 | };
16 |
--------------------------------------------------------------------------------
/test/fixtures/flags/watch/multi-config.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | module.exports = {
4 | arguments: [],
5 |
6 | config: [
7 | {
8 | entry: resolve(__dirname, '../../common/entry-a.js'),
9 | mode: 'development',
10 | },
11 | {
12 | entry: resolve(__dirname, '../../common/entry-b.js'),
13 | mode: 'development',
14 | watch: true,
15 | },
16 | ],
17 |
18 | group: 'advanced',
19 | };
20 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/basic/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const webpack = require('webpack');
4 |
5 | module.exports = {
6 | // mode: 'development',x
7 | context: __dirname,
8 | devtool: 'source-map',
9 | entry: './entry.js',
10 | output: {
11 | filename: './output.js',
12 | path: path.join(__dirname, '/dist'),
13 | },
14 | plugins: [new webpack.NamedModulesPlugin()],
15 | stats: 'none',
16 | };
17 |
--------------------------------------------------------------------------------
/test/tests/flags/progress.js:
--------------------------------------------------------------------------------
1 | const { apply, test, validate } = require('../../util');
2 |
3 | const fixture = 'progress/progress';
4 | const opts = { fixture };
5 |
6 | let config;
7 |
8 | test('--progress', module, () => {
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/SUPPORT.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🆘 Support, Help, and Advice
3 | about: 👉🏽 Need support, help, or advice? Don't open an issue! Head to StackOverflow or https://gitter.im/webpack/webpack.
4 |
5 | ---
6 |
7 | Hey there! If you need support, help, or advice then this is not the place to ask.
8 | Please visit [StackOverflow](https://stackoverflow.com/questions/tagged/webpack)
9 | or [the Webpack Gitter](https://gitter.im/webpack/webpack) instead.
10 |
--------------------------------------------------------------------------------
/test/fixtures/flags/module-bind/bind-pre.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | const loaderPath = resolve(__dirname, '../../common/loader-pre');
6 |
7 | module.exports = {
8 | arguments: ['--module-bind-pre', `js=${loaderPath}`],
9 |
10 | config: Object.assign({}, config, {
11 | entry: resolve(__dirname, '../../common/entry-a.js'),
12 | }),
13 |
14 | group: 'module',
15 | };
16 |
--------------------------------------------------------------------------------
/test/fixtures/flags/module-bind/bind-post.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | const loaderPath = resolve(__dirname, '../../common/loader-post');
6 |
7 | module.exports = {
8 | arguments: ['--module-bind-post', `js=${loaderPath}`],
9 |
10 | config: Object.assign({}, config, {
11 | entry: resolve(__dirname, '../../common/entry-a.js'),
12 | }),
13 |
14 | group: 'module',
15 | };
16 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/bail.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --bail > should apply #0 1`] = `
4 | Object {
5 | "bail": true,
6 | "entry": "/test/fixtures/flags/bail/entry.js",
7 | "mode": "development",
8 | "plugins": Array [
9 | NamedModulesPlugin {
10 | "options": Object {},
11 | },
12 | ],
13 | "reporter": "/test/fixtures/common/test-reporter.js",
14 | }
15 | `;
16 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/progress.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --progress > should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-a.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | NamedModulesPlugin {
9 | "options": Object {},
10 | },
11 | ],
12 | "progress": true,
13 | "reporter": "/test/fixtures/common/test-reporter.js",
14 | }
15 | `;
16 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/stylish.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: [],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | }),
11 |
12 | inspect: 'stdout',
13 |
14 | group: 'general',
15 | };
16 |
17 | // the test reporter is added by default in common fixtures
18 | delete module.exports.config.reporter;
19 |
--------------------------------------------------------------------------------
/test/fixtures/flags/reporter/basic.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--reporter', 'basic'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, '../../common/entry-a.js'),
10 | stats: {
11 | builtAt: false,
12 | hash: false,
13 | timings: false,
14 | },
15 | }),
16 |
17 | inspect: 'stdout',
18 |
19 | group: 'general',
20 | };
21 |
--------------------------------------------------------------------------------
/test/fixtures/flags/records/records-input-output.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: [
7 | '--records-input-path',
8 | './dist/records-input.json',
9 | '--records-output-path',
10 | './dist/records-output.json',
11 | ],
12 |
13 | config: Object.assign({}, config, {
14 | entry: resolve(__dirname, '../../common/entry-a.js'),
15 | }),
16 |
17 | group: 'advanced',
18 | };
19 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/big/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const webpack = require('webpack');
4 |
5 | module.exports = {
6 | // mode: 'development',x
7 | context: __dirname,
8 | devtool: 'source-map',
9 | entry: './entry.js',
10 | output: {
11 | filename: './output.js',
12 | path: path.join(__dirname, '/dist'),
13 | },
14 | performance: {
15 | hints: 'warning',
16 | },
17 | plugins: [new webpack.NamedModulesPlugin()],
18 | stats: 'none',
19 | };
20 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/problems/stylish-problems.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: [],
7 |
8 | config: Object.assign({}, config, {
9 | entry: resolve(__dirname, './entry-problems.js'),
10 | }),
11 |
12 | inspect: 'stdout',
13 |
14 | group: 'general',
15 | };
16 |
17 | // the test reporter is added by default in common fixtures
18 | delete module.exports.config.reporter;
19 |
--------------------------------------------------------------------------------
/test/fixtures/flags/config-name/multi-found.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | module.exports = {
4 | arguments: ['--config-name', 'multi-found'],
5 |
6 | config: [
7 | {
8 | entry: resolve(__dirname, '../../common/entry-a.js'),
9 | mode: 'development',
10 | name: 'bundle-a',
11 | },
12 | {
13 | entry: resolve(__dirname, '../../common/entry-b.js'),
14 | mode: 'development',
15 | name: 'multi-found',
16 | },
17 | ],
18 |
19 | group: 'config',
20 | };
21 |
--------------------------------------------------------------------------------
/test/fixtures/flags/optimize/optimize-max-chunks.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--optimize-max-chunks', '1000'],
7 |
8 | config: Object.assign({}, config, {
9 | entry: [
10 | resolve(__dirname, '../../common/entry-a.js'),
11 | resolve(__dirname, '../../common/entry-b.js'),
12 | resolve(__dirname, '../../common/entry-c.js'),
13 | ],
14 | }),
15 |
16 | group: 'optimization',
17 | };
18 |
--------------------------------------------------------------------------------
/test/fixtures/flags/resolve/resolve-loader-alias.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | const preLoaderPath = resolve(__dirname, '../../common/loader-pre');
6 |
7 | module.exports = {
8 | // TODO: no one knows how this works
9 | arguments: ['--resolve-loader-alias.aliased', `${preLoaderPath}`],
10 |
11 | config: Object.assign({}, config, {
12 | entry: resolve(__dirname, './entry-loader-alias.js'),
13 | }),
14 |
15 | group: 'resolver',
16 | };
17 |
--------------------------------------------------------------------------------
/test/fixtures/flags/config-name/single-object.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 | const WebpackCommandError = require('../../../../lib/WebpackCommandError');
5 |
6 | module.exports = {
7 | arguments: ['--config-name', 'single-object'],
8 |
9 | config: Object.assign({}, config, {
10 | entry: resolve(__dirname, '../../common/entry-a.js'),
11 | name: 'single-object',
12 | }),
13 |
14 | group: 'config',
15 |
16 | throws: WebpackCommandError,
17 | };
18 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/profile.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --profile > should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-a.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | NamedModulesPlugin {
9 | "options": Object {},
10 | },
11 | ],
12 | "profile": true,
13 | "reporter": "/test/fixtures/common/test-reporter.js",
14 | }
15 | `;
16 |
17 | exports[`Flags > --profile > should build #0 1`] = `"1c77bf93"`;
18 |
--------------------------------------------------------------------------------
/test/fixtures/flags/define/define.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const merge = require('merge-options');
4 | const { DefinePlugin } = require('webpack');
5 |
6 | const config = require('../../common/webpack.config');
7 |
8 | const plugins = [new DefinePlugin({ test: 'invalid' })];
9 |
10 | module.exports = {
11 | arguments: ['--define.DEFINE', `'valid'`],
12 |
13 | config: merge({}, config, {
14 | entry: resolve(__dirname, './entry.js'),
15 | plugins: config.plugins.concat(plugins),
16 | }),
17 |
18 | group: 'advanced',
19 | };
20 |
--------------------------------------------------------------------------------
/test/tests/flags/config.js:
--------------------------------------------------------------------------------
1 | const cli = require('../../../lib');
2 | const { prep, test, validate } = require('../../util');
3 |
4 | const fixture = 'config/config';
5 | const opts = { fixture };
6 |
7 | test('--config', module, () => {
8 | it(`should validate`, () => {
9 | expect(validate(opts)).toEqual(true);
10 | });
11 |
12 | it(`should build`, () => {
13 | const { argv } = prep({ fixture });
14 |
15 | return cli({ argv, entries: [], flags: argv }).then((result) => {
16 | expect(result).toMatchSnapshot();
17 | });
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/test/tests/flags/hot.js:
--------------------------------------------------------------------------------
1 | const { apply, build, test, validate } = require('../../util');
2 |
3 | const fixture = 'hot/hot';
4 | const opts = { fixture };
5 |
6 | let config;
7 |
8 | test('--hot', module, () => {
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 |
19 | it(`should build`, () =>
20 | build(config).then((result) => {
21 | expect(result).toMatchSnapshot();
22 | }));
23 | });
24 |
--------------------------------------------------------------------------------
/test/tests/flags/cache.js:
--------------------------------------------------------------------------------
1 | const { apply, build, test, validate } = require('../../util');
2 |
3 | const fixture = 'cache/cache';
4 | const opts = { fixture };
5 |
6 | let config;
7 |
8 | test('--cache', module, () => {
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 |
19 | it(`should build`, () =>
20 | build(config).then((result) => {
21 | expect(result).toMatchSnapshot();
22 | }));
23 | });
24 |
--------------------------------------------------------------------------------
/test/tests/flags/debug.js:
--------------------------------------------------------------------------------
1 | const { apply, build, test, validate } = require('../../util');
2 |
3 | const fixture = 'debug/debug';
4 | const opts = { fixture };
5 |
6 | let config;
7 |
8 | test('--debug', module, () => {
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 |
19 | it(`should build`, () =>
20 | build(config).then((result) => {
21 | expect(result).toMatchSnapshot();
22 | }));
23 | });
24 |
--------------------------------------------------------------------------------
/test/tests/flags/context.js:
--------------------------------------------------------------------------------
1 | const { apply, build, test, validate } = require('../../util');
2 |
3 | const fixture = 'context/context';
4 | const opts = { fixture };
5 |
6 | let config;
7 |
8 | test('--context', module, () => {
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 |
19 | it(`should build`, () =>
20 | build(config).then((result) => {
21 | expect(result).toMatchSnapshot();
22 | }));
23 | });
24 |
--------------------------------------------------------------------------------
/test/tests/commands/command.js:
--------------------------------------------------------------------------------
1 | const { test } = require('../../util');
2 | const Command = require('../../../lib/commands/Command');
3 |
4 | let command;
5 |
6 | test('help command', module, () => {
7 | it(`should instantiate`, () => {
8 | command = new Command();
9 | expect(command).toBeInstanceOf(Command);
10 | });
11 |
12 | it(`should display help`, () => {
13 | const result = command.help();
14 | expect(result).toMatchSnapshot();
15 | });
16 |
17 | it(`should run`, () => {
18 | const stub = () => command.run({});
19 | expect(stub).not.toThrow();
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/test/fixtures/common/test-reporter.js:
--------------------------------------------------------------------------------
1 | const Reporter = require('../../../lib/reporters/Reporter');
2 | const WebpackCommandError = require('../../../lib/WebpackCommandError');
3 |
4 | module.exports = class TestReporter extends Reporter {
5 | render(error, stats) {
6 | if (!stats) {
7 | return null;
8 | }
9 |
10 | if (stats.hasErrors()) {
11 | const info = stats.toJson();
12 | throw new WebpackCommandError(info.errors);
13 | }
14 |
15 | const result = stats.toString({
16 | builtAt: false,
17 | hash: false,
18 | timings: false,
19 | });
20 |
21 | return result;
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/test/fixtures/flags/config-name/multi-missing.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const WebpackCommandError = require('../../../../lib/WebpackCommandError');
4 |
5 | module.exports = {
6 | arguments: ['--config-name', 'multi-missing'],
7 |
8 | config: [
9 | {
10 | entry: resolve(__dirname, '../../common/entry-a.js'),
11 | mode: 'development',
12 | name: 'bundle-a',
13 | },
14 | {
15 | entry: resolve(__dirname, '../../common/entry-b.js'),
16 | mode: 'development',
17 | name: 'bundle-b',
18 | },
19 | ],
20 |
21 | group: 'config',
22 |
23 | throws: WebpackCommandError,
24 | };
25 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/nonstandard/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const StyleLintPlugin = require('stylelint-webpack-plugin');
4 | const webpack = require('webpack');
5 |
6 | module.exports = {
7 | // mode: 'development',x
8 | context: __dirname,
9 | devtool: 'source-map',
10 | entry: './entry.js',
11 | output: {
12 | filename: './output.js',
13 | path: path.join(__dirname, '/dist'),
14 | },
15 | plugins: [
16 | new webpack.NamedModulesPlugin(),
17 | new StyleLintPlugin({
18 | configFile: path.join(__dirname, '/.stylelintrc'),
19 | }),
20 | ],
21 | stats: 'none',
22 | };
23 |
--------------------------------------------------------------------------------
/test/tests/flags/plugin.js:
--------------------------------------------------------------------------------
1 | const { apply, build, crcDist, test, validate } = require('../../util');
2 |
3 | const fixture = 'plugin/plugin';
4 | const opts = { fixture };
5 |
6 | let config;
7 |
8 | test('--plugin', module, () => {
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 |
19 | it(`should build`, () =>
20 | build(config).then((result) => {
21 | expect(result).toMatchSnapshot();
22 | expect(crcDist()).toMatchSnapshot();
23 | }));
24 | });
25 |
--------------------------------------------------------------------------------
/test/tests/flags/provide.js:
--------------------------------------------------------------------------------
1 | const { apply, build, crcDist, test, validate } = require('../../util');
2 |
3 | const fixture = 'provide/provide';
4 | const opts = { fixture };
5 |
6 | let config;
7 |
8 | test('--provide', module, () => {
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 |
19 | it(`should build`, () =>
20 | build(config).then((result) => {
21 | expect(result).toMatchSnapshot();
22 | expect(crcDist()).toMatchSnapshot();
23 | }));
24 | });
25 |
--------------------------------------------------------------------------------
/test/tests/flags/target.js:
--------------------------------------------------------------------------------
1 | const { apply, build, crcDist, test, validate } = require('../../util');
2 |
3 | const fixture = 'target/target';
4 | const opts = { fixture };
5 |
6 | let config;
7 |
8 | test('--target', module, () => {
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 |
19 | it(`should build`, () =>
20 | build(config).then((result) => {
21 | expect(result).toMatchSnapshot();
22 | expect(crcDist()).toMatchSnapshot();
23 | }));
24 | });
25 |
--------------------------------------------------------------------------------
/test/tests/flags/prefetch.js:
--------------------------------------------------------------------------------
1 | const { apply, build, crcDist, test, validate } = require('../../util');
2 |
3 | const fixture = 'prefetch/prefetch';
4 | const opts = { fixture };
5 |
6 | let config;
7 |
8 | test('--prefetch', module, () => {
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 |
19 | it(`should build`, () =>
20 | build(config).then((result) => {
21 | expect(result).toMatchSnapshot();
22 | expect(crcDist()).toMatchSnapshot();
23 | }));
24 | });
25 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/json/json-multi.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: [],
7 |
8 | config: [
9 | Object.assign({}, config, {
10 | entry: resolve(__dirname, '../../common/entry-a.js'),
11 | reporter: 'json',
12 | }),
13 | Object.assign({}, config, {
14 | entry: [
15 | resolve(__dirname, '../../common/entry-b.js'),
16 | resolve(__dirname, '../../common/entry-c.js'),
17 | ],
18 | reporter: 'json',
19 | }),
20 | ],
21 |
22 | inspect: 'stdout',
23 |
24 | group: 'general',
25 | };
26 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/nonstandard/webpack.bad-rule.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const StyleLintPlugin = require('stylelint-webpack-plugin');
4 | const webpack = require('webpack');
5 |
6 | module.exports = {
7 | // mode: 'development',x
8 | context: __dirname,
9 | devtool: 'source-map',
10 | entry: './entry.js',
11 | output: {
12 | filename: './output.js',
13 | path: path.join(__dirname, '/dist'),
14 | },
15 | plugins: [
16 | new webpack.NamedModulesPlugin(),
17 | new StyleLintPlugin({
18 | configFile: path.join(__dirname, '/bad-rule.stylelintrc'),
19 | }),
20 | ],
21 | stats: 'none',
22 | };
23 |
--------------------------------------------------------------------------------
/test/tests/flags/define.js:
--------------------------------------------------------------------------------
1 | const { apply, build, distContains, test, validate } = require('../../util');
2 |
3 | const fixture = 'define/define';
4 | const opts = { fixture };
5 |
6 | let config;
7 |
8 | test('--define', module, () => {
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 |
19 | it(`should build`, () =>
20 | build(config).then((result) => {
21 | expect(distContains(`result: 'valid'`)).toBe(true);
22 | expect(result).toMatchSnapshot();
23 | }));
24 | });
25 |
--------------------------------------------------------------------------------
/test/fixtures/flags/module-bind/bind-all.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | const postLoaderPath = resolve(__dirname, '../../common/loader-post');
6 | const preLoaderPath = resolve(__dirname, '../../common/loader-pre');
7 |
8 | module.exports = {
9 | arguments: [
10 | '--module-bind-pre',
11 | `js=${preLoaderPath}`,
12 | '--module-bind',
13 | 'json',
14 | '--module-bind-post',
15 | `js=${postLoaderPath}`,
16 | ],
17 |
18 | config: Object.assign({}, config, {
19 | entry: resolve(__dirname, '../../common/entry-a.js'),
20 | }),
21 |
22 | group: 'module',
23 | };
24 |
--------------------------------------------------------------------------------
/test/fixtures/flags/config-name/multi-duplicate.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | module.exports = {
4 | arguments: ['--config-name', 'multi-duplicate'],
5 |
6 | config: [
7 | {
8 | entry: resolve(__dirname, '../../common/entry-a.js'),
9 | mode: 'development',
10 | name: 'bundle-a',
11 | },
12 | {
13 | entry: resolve(__dirname, '../../common/entry-b.js'),
14 | mode: 'development',
15 | name: 'multi-duplicate',
16 | },
17 | {
18 | entry: resolve(__dirname, '../../common/entry-c.js'),
19 | mode: 'development',
20 | name: 'multi-duplicate',
21 | },
22 | ],
23 |
24 | group: 'config',
25 | };
26 |
--------------------------------------------------------------------------------
/test/tests/flags/profile.js:
--------------------------------------------------------------------------------
1 | const { apply, build, crcDist, test, validate } = require('../../util');
2 |
3 | const fixture = 'profile/profile';
4 | const opts = { fixture };
5 |
6 | let config;
7 |
8 | test('--profile', module, () => {
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 |
19 | it(`should build`, () =>
20 | build(config).then((result) => {
21 | expect(/factory:\d+ms building:\d+ms = \d+ms/.test(result)).toBe(true);
22 | expect(crcDist()).toMatchSnapshot();
23 | }));
24 | });
25 |
--------------------------------------------------------------------------------
/test/tests/flags/bail.js:
--------------------------------------------------------------------------------
1 | const ModuleNotFoundError = require('webpack/lib/ModuleNotFoundError');
2 |
3 | const { apply, build, test, validate } = require('../../util');
4 |
5 | const fixture = 'bail/bail';
6 | const opts = { fixture };
7 |
8 | let config;
9 |
10 | test('--bail', module, () => {
11 | it(`should validate`, () => {
12 | expect(validate(opts)).toEqual(true);
13 | });
14 |
15 | it(`should apply`, () => {
16 | config = apply(opts);
17 |
18 | expect(config).toMatchSnapshot();
19 | });
20 |
21 | it(`should build, fail, and bail`, () =>
22 | build(config).catch((error) => {
23 | expect(error).toEqual(expect.any(ModuleNotFoundError));
24 | }));
25 | });
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/FEATURE.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: ✨ Feature Request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 |
17 |
18 | * Operating System:
19 | * Node Version:
20 | * NPM Version:
21 | * webpack Version:
22 | * webpack-command Version:
23 |
24 |
25 | ### Feature Proposal
26 |
27 |
28 |
29 | ### Feature Use Case
--------------------------------------------------------------------------------
/test/fixtures/flags/reporter/basic-multi.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: ['--reporter', 'basic'],
7 |
8 | config: [
9 | Object.assign({}, config, {
10 | entry: resolve(__dirname, '../../common/entry-a.js'),
11 | }),
12 | Object.assign({}, config, {
13 | entry: [
14 | resolve(__dirname, '../../common/entry-b.js'),
15 | resolve(__dirname, '../../common/entry-c.js'),
16 | ],
17 | stats: {
18 | builtAt: false,
19 | hash: false,
20 | timings: false,
21 | },
22 | }),
23 | ],
24 |
25 | inspect: 'stdout',
26 |
27 | group: 'general',
28 | };
29 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/multi/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const webpack = require('webpack');
4 |
5 | module.exports = [
6 | {
7 | context: __dirname,
8 | entry: './client.js',
9 | output: {
10 | filename: 'client.js',
11 | path: path.join(__dirname, '/dist/client'),
12 | publicPath: '/static/',
13 | },
14 | plugins: [new webpack.NamedModulesPlugin()],
15 | stats: 'none',
16 | },
17 | {
18 | context: __dirname,
19 | entry: './server.js',
20 | output: {
21 | filename: 'server.js',
22 | path: path.join(__dirname, '/dist/server'),
23 | },
24 | plugins: [new webpack.NamedModulesPlugin()],
25 | stats: 'none',
26 | },
27 | ];
28 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/context.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --context > should apply #0 1`] = `
4 | Object {
5 | "context": "/test/fixtures/common",
6 | "entry": "./entry-a.js",
7 | "mode": "development",
8 | "plugins": Array [
9 | NamedModulesPlugin {
10 | "options": Object {},
11 | },
12 | ],
13 | "reporter": "/test/fixtures/common/test-reporter.js",
14 | }
15 | `;
16 |
17 | exports[`Flags > --context > should build #0 1`] = `
18 | "Version: webpack 4.14.0
19 | Asset Size Chunks Chunk Names
20 | main.js 3.8 KiB main [emitted] main
21 | Entrypoint main = main.js
22 | [./entry-a.js] 41 bytes {main} [built]"
23 | `;
24 |
--------------------------------------------------------------------------------
/test/tests/flags/mode.js:
--------------------------------------------------------------------------------
1 | const { apply, build, crcDist, test, validate } = require('../../util');
2 |
3 | test('--mode', module, () => {
4 | for (const name of ['dev', 'prod']) {
5 | const fixture = `mode/${name}`;
6 | const opts = { fixture };
7 |
8 | let config;
9 |
10 | it(`${name} should validate`, () => {
11 | expect(validate(opts)).toEqual(true);
12 | });
13 |
14 | it(`${name} should apply`, () => {
15 | config = apply(opts);
16 |
17 | expect(config).toMatchSnapshot();
18 | });
19 |
20 | it(`${name} should build`, () =>
21 | build(config).then((result) => {
22 | expect(result).toMatchSnapshot();
23 | expect(crcDist()).toMatchSnapshot();
24 | }));
25 | }
26 | });
27 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/stylish-multi.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const config = require('../../common/webpack.config');
4 |
5 | module.exports = {
6 | arguments: [],
7 |
8 | config: [
9 | Object.assign({}, config, {
10 | entry: resolve(__dirname, '../../common/entry-a.js'),
11 | }),
12 | Object.assign({}, config, {
13 | entry: [
14 | resolve(__dirname, '../../common/entry-b.js'),
15 | resolve(__dirname, '../../common/entry-c.js'),
16 | ],
17 | }),
18 | ],
19 |
20 | inspect: 'stdout',
21 |
22 | group: 'general',
23 | };
24 |
25 | // the test reporter is added by default in common fixtures
26 | for (const conf of module.exports.config) {
27 | delete conf.reporter;
28 | }
29 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/cache.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --cache > should apply #0 1`] = `
4 | Object {
5 | "cache": true,
6 | "entry": "/test/fixtures/common/entry-a.js",
7 | "mode": "development",
8 | "plugins": Array [
9 | NamedModulesPlugin {
10 | "options": Object {},
11 | },
12 | ],
13 | "reporter": "/test/fixtures/common/test-reporter.js",
14 | }
15 | `;
16 |
17 | exports[`Flags > --cache > should build #0 1`] = `
18 | "Version: webpack 4.14.0
19 | Asset Size Chunks Chunk Names
20 | main.js 3.92 KiB main [emitted] main
21 | Entrypoint main = main.js
22 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
23 | `;
24 |
--------------------------------------------------------------------------------
/test/tests/flags/optimize.js:
--------------------------------------------------------------------------------
1 | const { apply, build, test, validate } = require('../../util');
2 |
3 | test('--optimize-*', module, () => {
4 | for (const name of ['max-chunks', 'min-chunk-size', 'minimize']) {
5 | const fixture = `optimize/optimize-${name}`;
6 | const opts = { fixture };
7 |
8 | let config;
9 |
10 | it(`${name} should validate`, () => {
11 | expect(validate(opts)).toEqual(true);
12 | });
13 |
14 | it(`${name} should apply`, () => {
15 | config = apply(opts);
16 |
17 | expect(config).toMatchSnapshot();
18 | });
19 |
20 | it(`${name} should build`, () =>
21 | build(config).then((result) => {
22 | expect(result.replace(/\d+\.\d+ KiB/, '')).toMatchSnapshot();
23 | }));
24 | }
25 | });
26 |
--------------------------------------------------------------------------------
/test/tests/flags/records.js:
--------------------------------------------------------------------------------
1 | const { apply, build, crcDist, test, validate } = require('../../util');
2 |
3 | test('--records-*', module, () => {
4 | for (const name of ['input-output', 'path']) {
5 | const fixture = `records/records-${name}`;
6 | const opts = { fixture };
7 |
8 | let config;
9 |
10 | it(`${name} should validate`, () => {
11 | expect(validate(opts)).toEqual(true);
12 | });
13 |
14 | it(`${name} should apply`, () => {
15 | config = apply(opts);
16 |
17 | expect(config).toMatchSnapshot();
18 | });
19 |
20 | it(`${name} should build`, () =>
21 | build(config).then((result) => {
22 | expect(result).toMatchSnapshot();
23 | expect(crcDist()).toMatchSnapshot();
24 | }));
25 | }
26 | });
27 |
--------------------------------------------------------------------------------
/lib/flags/module.js:
--------------------------------------------------------------------------------
1 | const { bind } = require('./util');
2 |
3 | module.exports = {
4 | apply(argv, options) {
5 | let result = bind(argv.moduleBind, undefined, options); // eslint-disable-line no-undefined
6 | result = bind(argv.moduleBindPre, 'pre', result);
7 | result = bind(argv.moduleBindPost, 'post', result);
8 |
9 | return result;
10 | },
11 |
12 | flags: {
13 | 'module-bind': {
14 | desc: 'Bind an extension to a loader',
15 | type: 'string',
16 | },
17 | 'module-bind-post': {
18 | desc: 'Bind an extension to a postLoader',
19 | type: 'string',
20 | },
21 | 'module-bind-pre': {
22 | desc: 'Bind an extension to a preLoader',
23 | type: 'string',
24 | },
25 | },
26 |
27 | name: 'Modules',
28 | };
29 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/loaders/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 |
5 | module.exports = {
6 | // mode: 'development',
7 | context: __dirname,
8 | devtool: 'source-map',
9 | entry: './entry.js',
10 | output: {
11 | filename: './output.js',
12 | path: path.join(__dirname, '/dist'),
13 | },
14 | plugins: [
15 | new HtmlWebpackPlugin({
16 | title: 'Fixture',
17 | }),
18 | ],
19 | stats: 'none',
20 | module: {
21 | rules: [
22 | {
23 | test: /\.(png|jpg|gif)$/,
24 | use: [
25 | {
26 | loader: 'file-loader',
27 | options: {},
28 | },
29 | ],
30 | },
31 | ],
32 | },
33 | };
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/config-name.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --config-name > multi-duplicate should find config #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-b.js",
6 | "mode": "development",
7 | "name": "multi-duplicate",
8 | }
9 | `;
10 |
11 | exports[`Flags > --config-name > multi-found should find config #0 1`] = `
12 | Object {
13 | "entry": "/test/fixtures/common/entry-b.js",
14 | "mode": "development",
15 | "name": "multi-found",
16 | }
17 | `;
18 |
19 | exports[`Flags > --config-name > single-array should find config #0 1`] = `
20 | Object {
21 | "entry": "/test/fixtures/common/entry-a.js",
22 | "mode": "development",
23 | "name": "single-object",
24 | }
25 | `;
26 |
--------------------------------------------------------------------------------
/test/fixtures/progress/entry.js:
--------------------------------------------------------------------------------
1 | require('@webpack-contrib/config-loader');
2 | require('@webpack-contrib/schema-utils');
3 | require('camelcase');
4 | require('chalk');
5 | require('debug');
6 | require('decamelize');
7 | require('import-local');
8 | require('isobject');
9 | require('loader-utils');
10 | require('log-symbols');
11 | require('loud-rejection');
12 | require('meant');
13 | require('meow');
14 | require('merge-options');
15 | require('object.values');
16 | require('opn');
17 | require('ora');
18 | require('plur');
19 | require('pretty-bytes');
20 | require('strip-ansi');
21 | require('text-table');
22 | require('titleize');
23 | require('update-notifier');
24 | require('v8-compile-cache');
25 | require('webpack-log');
26 | require('wordwrap');
27 |
28 | module.exports = {
29 | name: 'entry-a',
30 | };
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/DOCS.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 📚 Documentation
3 | about: Are the docs lacking or missing something? Do they need some new 🔥 hotness? Tell us here.
4 |
5 | ---
6 |
7 |
17 |
18 | Documentation Is:
19 |
20 |
21 |
22 | - [ ] Missing
23 | - [ ] Needed
24 | - [ ] Confusing
25 | - [ ] Not Sure?
26 |
27 |
28 | ### Please Explain in Detail...
29 |
30 |
31 | ### Your Proposal for Changes
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/target.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --target > should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-a.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | NamedModulesPlugin {
9 | "options": Object {},
10 | },
11 | ],
12 | "reporter": "/test/fixtures/common/test-reporter.js",
13 | "target": "node",
14 | }
15 | `;
16 |
17 | exports[`Flags > --target > should build #0 1`] = `
18 | "Version: webpack 4.14.0
19 | Asset Size Chunks Chunk Names
20 | main.js 3.92 KiB main [emitted] main
21 | Entrypoint main = main.js
22 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
23 | `;
24 |
25 | exports[`Flags > --target > should build #1 1`] = `"1c77bf93"`;
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/MODIFICATION.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🔧 Modification Request
3 | about: Would you like something work differently? Have an alternative approach? This is the template for you.
4 |
5 | ---
6 |
7 |
17 |
18 | * Operating System:
19 | * Node Version:
20 | * NPM Version:
21 | * webpack Version:
22 | * webpack-command Version:
23 |
24 |
25 | ### Expected Behavior / Situation
26 |
27 |
28 |
29 | ### Actual Behavior / Situation
30 |
31 |
32 |
33 | ### Modification Proposal
--------------------------------------------------------------------------------
/test/tests/flags/resolve.js:
--------------------------------------------------------------------------------
1 | const { apply, build, crcDist, test, validate } = require('../../util');
2 |
3 | test('--resolve-*', module, () => {
4 | for (const name of [
5 | 'resolve-alias',
6 | 'resolve-extensions',
7 | 'resolve-loader-alias',
8 | ]) {
9 | const fixture = `resolve/${name}`;
10 | const opts = { fixture };
11 |
12 | let config;
13 |
14 | it(`${name} reporter should validate`, () => {
15 | expect(validate(opts)).toEqual(true);
16 | });
17 |
18 | it(`${name} reporter should apply`, () => {
19 | config = apply(opts);
20 |
21 | expect(config).toMatchSnapshot();
22 | });
23 |
24 | it(`${name} reporter should build`, () =>
25 | build(config).then((result) => {
26 | expect(result).toMatchSnapshot();
27 | expect(crcDist()).toMatchSnapshot();
28 | }));
29 | }
30 | });
31 |
--------------------------------------------------------------------------------
/docs/HelpCommand.md:
--------------------------------------------------------------------------------
1 | # Help Command
2 |
3 | 🆘 Displays help for a given installed `webpack-command` command.
4 |
5 | ```console
6 | $ webpack help Help
7 |
8 | Displays help for a given installed webpack command.
9 |
10 | Usage
11 | $ webpack help
12 |
13 | Examples
14 | $ webpack help
15 | $ webpack help init
16 | $ webpack help serve
17 | ```
18 |
19 | ## Getting Started
20 |
21 | > This command is included by default with `webpack-command`
22 |
23 | ## Usage
24 |
25 | To open the [webpack documentation](https://webpack.js.org) in your default
26 | browser run:
27 |
28 | ```console
29 | $ webpack help
30 | ```
31 |
32 | To display the help information for an available command run:
33 |
34 | ```console
35 | $ webpack help
36 | ```
37 |
38 | Where `` is the name of the command you want to show help for.
39 |
40 | ## That's All, Folks
--------------------------------------------------------------------------------
/test/tests/flags/devtool.js:
--------------------------------------------------------------------------------
1 | const { existsSync: exists } = require('fs');
2 | const { resolve } = require('path');
3 |
4 | const { apply, build, crcDist, test, validate } = require('../../util');
5 |
6 | const fixture = 'devtool/devtool';
7 | const opts = { fixture };
8 |
9 | let config;
10 |
11 | test('--devtool', module, () => {
12 | it(`should validate`, () => {
13 | expect(validate(opts)).toEqual(true);
14 | });
15 |
16 | it(`should apply`, () => {
17 | config = apply(opts);
18 |
19 | expect(config).toMatchSnapshot();
20 | });
21 |
22 | it(`should build`, () =>
23 | build(config).then((result) => {
24 | const mapPath = resolve(__dirname, '../../../dist/main.js.map');
25 | expect(exists(mapPath));
26 | expect(result).toMatchSnapshot();
27 | expect(crcDist()).toMatchSnapshot();
28 | expect(crcDist(mapPath)).toMatchSnapshot();
29 | }));
30 | });
31 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/hot.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --hot > should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-a.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | HotModuleReplacementPlugin {
9 | "fullBuildTimeout": 200,
10 | "multiStep": undefined,
11 | "options": Object {},
12 | "requestTimeout": 10000,
13 | },
14 | NamedModulesPlugin {
15 | "options": Object {},
16 | },
17 | ],
18 | "reporter": "/test/fixtures/common/test-reporter.js",
19 | }
20 | `;
21 |
22 | exports[`Flags > --hot > should build #0 1`] = `
23 | "Version: webpack 4.14.0
24 | Asset Size Chunks Chunk Names
25 | main.js 28.9 KiB main [emitted] main
26 | Entrypoint main = main.js
27 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
28 | `;
29 |
--------------------------------------------------------------------------------
/test/tests/flags/reporter.js:
--------------------------------------------------------------------------------
1 | const strip = require('strip-ansi');
2 |
3 | const { apply, build, test, validate } = require('../../util');
4 |
5 | test('--reporter', module, () => {
6 | for (const name of ['basic', 'basic-multi']) {
7 | const fixture = `reporter/${name}`;
8 | const opts = { fixture };
9 |
10 | let config;
11 |
12 | it(`${name} reporter should validate`, () => {
13 | expect(validate(opts)).toEqual(true);
14 | });
15 |
16 | it(`${name} reporter should apply`, () => {
17 | config = apply(opts);
18 |
19 | expect(config).toMatchSnapshot();
20 | });
21 |
22 | it(`${name} reporter should build`, () =>
23 | build(config).then((result) => {
24 | expect(
25 | strip(result)
26 | .replace(/Δt \d+ms/g, '')
27 | .replace(/\d+\.\d+ KiB/g, '')
28 | ).toMatchSnapshot();
29 | }));
30 | }
31 | });
32 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/debug.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --debug > should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-a.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | LoaderOptionsPlugin {
9 | "options": Object {
10 | "debug": true,
11 | "test": Object {
12 | "test": [Function],
13 | },
14 | },
15 | },
16 | NamedModulesPlugin {
17 | "options": Object {},
18 | },
19 | ],
20 | "reporter": "/test/fixtures/common/test-reporter.js",
21 | }
22 | `;
23 |
24 | exports[`Flags > --debug > should build #0 1`] = `
25 | "Version: webpack 4.14.0
26 | Asset Size Chunks Chunk Names
27 | main.js 3.92 KiB main [emitted] main
28 | Entrypoint main = main.js
29 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
30 | `;
31 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | const Configuration = {
3 | extends: ['@commitlint/config-conventional'],
4 |
5 | rules: {
6 | 'body-leading-blank': [1, 'always'],
7 | 'footer-leading-blank': [1, 'always'],
8 | 'header-max-length': [2, 'always', 72],
9 | 'scope-case': [2, 'always', 'lower-case'],
10 | 'subject-case': [2, 'never', ['sentence-case', 'start-case', 'pascal-case', 'upper-case']],
11 | 'subject-empty': [2, 'never'],
12 | 'subject-full-stop': [2, 'never', '.'],
13 | 'type-case': [2, 'always', 'lower-case'],
14 | 'type-empty': [2, 'never'],
15 | 'type-enum': [2, 'always', [
16 | 'build',
17 | 'chore',
18 | 'ci',
19 | 'docs',
20 | 'feat',
21 | 'fix',
22 | 'perf',
23 | 'refactor',
24 | 'revert',
25 | 'style',
26 | 'test',
27 | ],
28 | ],
29 | },
30 | };
31 |
32 | module.exports = Configuration;
33 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/provide.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --provide > should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-a.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | ProvidePlugin {
9 | "definitions": Object {
10 | "$": "jquery",
11 | "jQuery": "jquery",
12 | },
13 | },
14 | NamedModulesPlugin {
15 | "options": Object {},
16 | },
17 | ],
18 | "reporter": "/test/fixtures/common/test-reporter.js",
19 | }
20 | `;
21 |
22 | exports[`Flags > --provide > should build #0 1`] = `
23 | "Version: webpack 4.14.0
24 | Asset Size Chunks Chunk Names
25 | main.js 3.92 KiB main [emitted] main
26 | Entrypoint main = main.js
27 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
28 | `;
29 |
30 | exports[`Flags > --provide > should build #1 1`] = `"1c77bf93"`;
31 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/define.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --define > should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/flags/define/entry.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | DefinePlugin {
9 | "definitions": Object {
10 | "DEFINE": "'valid'",
11 | },
12 | },
13 | NamedModulesPlugin {
14 | "options": Object {},
15 | },
16 | DefinePlugin {
17 | "definitions": Object {
18 | "test": "invalid",
19 | },
20 | },
21 | ],
22 | "reporter": "/test/fixtures/common/test-reporter.js",
23 | }
24 | `;
25 |
26 | exports[`Flags > --define > should build #0 1`] = `
27 | "Version: webpack 4.14.0
28 | Asset Size Chunks Chunk Names
29 | main.js 4 KiB main [emitted] main
30 | Entrypoint main = main.js
31 | [./test/fixtures/flags/define/entry.js] 91 bytes {main} [built]"
32 | `;
33 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/devtool.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --devtool > should apply #0 1`] = `
4 | Object {
5 | "devtool": "cheap-source-map",
6 | "entry": "/test/fixtures/common/entry-a.js",
7 | "mode": "development",
8 | "plugins": Array [
9 | NamedModulesPlugin {
10 | "options": Object {},
11 | },
12 | ],
13 | "reporter": "/test/fixtures/common/test-reporter.js",
14 | }
15 | `;
16 |
17 | exports[`Flags > --devtool > should build #0 1`] = `
18 | "Version: webpack 4.14.0
19 | Asset Size Chunks Chunk Names
20 | main.js 3.88 KiB main [emitted] main
21 | main.js.map 3.59 KiB main [emitted] main
22 | Entrypoint main = main.js main.js.map
23 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
24 | `;
25 |
26 | exports[`Flags > --devtool > should build #1 1`] = `"dc2cf76c"`;
27 |
28 | exports[`Flags > --devtool > should build #2 1`] = `"dccd936"`;
29 |
--------------------------------------------------------------------------------
/test/tests/flags/config-name.js:
--------------------------------------------------------------------------------
1 | const { distill } = require('../../../lib/config');
2 | const { prep, test, validate } = require('../../util');
3 |
4 | const fixtures = [
5 | 'multi-duplicate',
6 | 'multi-found',
7 | 'multi-missing',
8 | 'single-array',
9 | 'single-object',
10 | ];
11 |
12 | test('--config-name', module, () => {
13 | for (const name of fixtures) {
14 | const opts = {
15 | fixture: `config-name/${name}`,
16 | };
17 | const { argv, fixture } = prep(opts);
18 |
19 | it(`${name} should validate`, () => {
20 | expect(validate(opts)).toEqual(true);
21 | });
22 |
23 | // eslint-disable-next-line arrow-body-style
24 | it(`${name} should ${fixture.throws ? 'throw' : 'find config'}`, () => {
25 | const stub = () => distill(argv, fixture.config, {});
26 |
27 | if (fixture.throws) {
28 | expect(stub).toThrow(fixture.throws);
29 | } else {
30 | expect(stub()).toMatchSnapshot();
31 | }
32 | });
33 | }
34 | });
35 |
--------------------------------------------------------------------------------
/lib/reporters/JsonReporter.js:
--------------------------------------------------------------------------------
1 | const weblog = require('webpack-log');
2 |
3 | const WebpackCommandError = require('../WebpackCommandError');
4 |
5 | const Reporter = require('./Reporter');
6 |
7 | module.exports = class JsonReporter extends Reporter {
8 | constructor(...args) {
9 | super(...args);
10 |
11 | const log = weblog({ name: 'webpack', id: 'webpack-command' });
12 | this.originalLevel = log.level;
13 | log.level = 'silent';
14 | this.log = log;
15 | }
16 |
17 | /* istanbul ignore next */
18 | progress() {
19 | throw new WebpackCommandError(
20 | 'Build progress display is not supported when using the JSON reporter'
21 | );
22 | }
23 |
24 | render(error, stats) {
25 | if (error) {
26 | return error;
27 | }
28 |
29 | const json = stats.toJson();
30 | const result = JSON.stringify(json, null, 2);
31 |
32 | process.stdout.write(result);
33 |
34 | this.log.level = this.originalLevel;
35 |
36 | return result;
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/prefetch.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --prefetch > should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/flags/prefetch/entry.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | PrefetchPlugin {
9 | "request": "./test/fixtures/flags/prefetch/dependency.js",
10 | },
11 | NamedModulesPlugin {
12 | "options": Object {},
13 | },
14 | ],
15 | "reporter": "/test/fixtures/common/test-reporter.js",
16 | }
17 | `;
18 |
19 | exports[`Flags > --prefetch > should build #0 1`] = `
20 | "Version: webpack 4.14.0
21 | Asset Size Chunks Chunk Names
22 | main.js 4.56 KiB main [emitted] main
23 | Entrypoint main = main.js
24 | [./test/fixtures/flags/prefetch/dependency.js] 53 bytes {main} [built] [prefetched]
25 | [./test/fixtures/flags/prefetch/entry.js] 119 bytes {main} [built]"
26 | `;
27 |
28 | exports[`Flags > --prefetch > should build #1 1`] = `"9933bca7"`;
29 |
--------------------------------------------------------------------------------
/lib/flags/config.js:
--------------------------------------------------------------------------------
1 | const merge = require('merge-options');
2 |
3 | module.exports = {
4 | apply(argv, options) {
5 | const result = {};
6 |
7 | if (argv.configRegister) {
8 | /* istanbul ignore next */
9 | // eslint-disable-next-line no-param-reassign
10 | argv.require = argv.configRegister;
11 | }
12 |
13 | if (argv.mode) {
14 | result.mode = argv.mode;
15 | }
16 |
17 | return merge(options, result);
18 | },
19 |
20 | flags: {
21 | config: {
22 | desc: 'Path to the config file',
23 | type: 'string',
24 | },
25 | 'config-name': {
26 | desc: 'Name of the config to use',
27 | type: 'string',
28 | },
29 | 'config-register': {
30 | alias: 'r',
31 | desc: '',
32 | deprecated: '--require',
33 | type: ['string', 'array'],
34 | },
35 | mode: {
36 | desc: 'Specifies the build mode to use; development or production',
37 | type: 'string',
38 | },
39 | },
40 |
41 | name: 'Configuration File',
42 | };
43 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
10 |
11 | This PR contains a:
12 |
13 | - [ ] **bugfix**
14 | - [ ] new **feature**
15 | - [ ] **code refactor**
16 | - [ ] **test update**
17 | - [ ] **typo fix**
18 | - [ ] **metadata update**
19 |
20 | ### Motivation / Use-Case
21 |
22 |
27 |
28 | ### Breaking Changes
29 |
30 |
34 |
35 | ### Additional Info
36 |
--------------------------------------------------------------------------------
/test/tests/flags/output.js:
--------------------------------------------------------------------------------
1 | const { apply, build, test, validate } = require('../../util');
2 |
3 | const fixtures = [
4 | 'output-chunk-filename',
5 | 'output-filename',
6 | 'output-jsonp-function',
7 | 'output-library-target',
8 | 'output-library',
9 | 'output-path',
10 | 'output-pathinfo',
11 | 'output-public-path',
12 | 'output-source-map-filename',
13 | 'output',
14 | ];
15 |
16 | test('--output-*', module, () => {
17 | for (const name of fixtures) {
18 | const fixture = `output/${name}`;
19 | const opts = { fixture };
20 |
21 | let config;
22 |
23 | it(`${name} should validate`, () => {
24 | expect(validate(opts)).toEqual(true);
25 | });
26 |
27 | it(`${name} should apply`, () => {
28 | config = apply(opts);
29 |
30 | expect(config).toMatchSnapshot();
31 | });
32 |
33 | it(`${name} should build`, () =>
34 | build(config).then((result) => {
35 | expect(result).toMatchSnapshot();
36 | // expect(crcDist()).toMatchSnapshot();
37 | }));
38 | }
39 | });
40 |
--------------------------------------------------------------------------------
/lib/commands/index.js:
--------------------------------------------------------------------------------
1 | const { readFileSync: read } = require('fs');
2 | const { join } = require('path');
3 |
4 | const { CommandError } = require('./Command');
5 |
6 | function load() {
7 | const dataPath = join(__dirname, '../../data/commands.json');
8 | const dataFile = read(dataPath, 'utf-8');
9 | const commands = JSON.parse(dataFile);
10 |
11 | for (const command of Object.keys(commands)) {
12 | const commandModule = commands[command];
13 | let CommandClass;
14 |
15 | try {
16 | // eslint-disable-next-line global-require, import/no-dynamic-require
17 | CommandClass = require(commandModule);
18 | } catch (e) {
19 | throw new CommandError(
20 | `The command module '${commandModule}' was not found.`
21 | );
22 | }
23 |
24 | commands[command] = new CommandClass();
25 | }
26 |
27 | return commands;
28 | }
29 |
30 | module.exports = {
31 | CommandError,
32 | help() {
33 | const result = Object.keys(load())
34 | .sort()
35 | .join('\n ');
36 |
37 | return ` ${result}`;
38 | },
39 |
40 | load,
41 | };
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright JS Foundation and other contributors
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | 'Software'), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/test/tests/flags/run-mode.js:
--------------------------------------------------------------------------------
1 | const { apply, build, crcDist, test, validate } = require('../../util');
2 |
3 | test('--run-dev', module, () => {
4 | const fixture = 'run-mode/run-dev';
5 | const opts = { fixture };
6 |
7 | let config;
8 |
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 |
19 | it(`should build`, () =>
20 | build(config).then((result) => {
21 | expect(result).toMatchSnapshot();
22 | expect(crcDist()).toMatchSnapshot();
23 | }));
24 | });
25 |
26 | test('--run-prod', module, () => {
27 | const fixture = 'run-mode/run-prod';
28 | const opts = { fixture };
29 |
30 | let config;
31 |
32 | it(`should validate`, () => {
33 | expect(validate(opts)).toEqual(true);
34 | });
35 |
36 | it(`should apply`, () => {
37 | config = apply(opts);
38 |
39 | expect(config).toMatchSnapshot();
40 | });
41 |
42 | it(`should build`, () =>
43 | build(config).then((result) => {
44 | expect(result).toMatchSnapshot();
45 | expect(crcDist()).toMatchSnapshot();
46 | }));
47 | });
48 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | const updateNotifier = require('update-notifier');
2 | const weblog = require('webpack-log');
3 |
4 | const pkg = require('../package.json');
5 |
6 | const Command = require('./commands/Command');
7 | const compiler = require('./compiler');
8 | const { load } = require('./config');
9 | const parseEntries = require('./entry');
10 | const { apply } = require('./flags');
11 |
12 | module.exports = (cli) => {
13 | updateNotifier({ pkg }).notify();
14 |
15 | process.env.WEBPACK_COMMAND = true;
16 |
17 | const { argv } = cli;
18 | const log = weblog({
19 | name: 'webpack',
20 | id: 'webpack-command',
21 | level: argv.logLevel || 'info',
22 | timestamp: argv.logTime,
23 | });
24 |
25 | const options = apply(argv, {});
26 | const entry = parseEntries(cli);
27 |
28 | if (entry) {
29 | options.entry = entry;
30 | }
31 |
32 | if (!options) {
33 | process.exit(1);
34 | }
35 |
36 | /* istanbul ignore next */
37 | for (const sig of ['SIGINT', 'SIGTERM']) {
38 | process.on(sig, () => {
39 | // eslint-disable-line no-loop-func
40 | log.info(`Process Ended via ${sig}`);
41 | process.exit(0);
42 | });
43 | }
44 |
45 | return load(argv, options).then((target) => compiler(target).run());
46 | };
47 |
48 | module.exports.Command = Command;
49 |
--------------------------------------------------------------------------------
/test/tests/commands/__snapshots__/teach.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`teach command > should forget module #0 1`] = `
4 | "{
5 | \\"help\\": \\"./HelpCommand\\",
6 | \\"teach\\": \\"./TeachCommand\\"
7 | }"
8 | `;
9 |
10 | exports[`teach command > should learn module #0 1`] = `
11 | "{
12 | \\"help\\": \\"./HelpCommand\\",
13 | \\"teach\\": \\"./TeachCommand\\",
14 | \\"test\\": \\"/test/fixtures/commands/TestCommand.js\\"
15 | }"
16 | `;
17 |
18 | exports[`teach command > should throw for duplicate modules #0 1`] = `"The 'test' command was already added via /test/fixtures/commands/TestCommand.js. Use \`webpack teach --command test --forget\` and try again."`;
19 |
20 | exports[`teach command > should throw for missing --module #0 1`] = `"The command module 'missing-module' was not found."`;
21 |
22 | exports[`teach command > should throw for no --command value #0 1`] = `"The value of --command must be a String."`;
23 |
24 | exports[`teach command > should throw for no --module #0 1`] = `"The --module flag is required."`;
25 |
26 | exports[`teach command > should throw for no --module value #0 1`] = `"The value of --module must be a String."`;
27 |
28 | exports[`teach command > should throw for no args #0 1`] = `"The --command flag is required."`;
29 |
--------------------------------------------------------------------------------
/lib/entry.js:
--------------------------------------------------------------------------------
1 | const isObject = require('isobject');
2 |
3 | module.exports = (cli) => {
4 | const { flags: argv, entries } = cli;
5 | let entry;
6 | const flag = argv.entry;
7 | const assertArray = () => {
8 | if (!entry) {
9 | entry = { main: [] };
10 | } else if (!entry.main || !Array.isArray(entry.main)) {
11 | entry.main = [entry.main];
12 | }
13 | };
14 |
15 | // if entries were specified as input, they take precedence
16 | if (entries.length) {
17 | entry = { main: entries.length > 1 ? entries : entries[0] };
18 | }
19 |
20 | if (flag) {
21 | if (isObject(flag)) {
22 | if (flag.main) {
23 | assertArray();
24 | entry.main = entry.main.concat(flag.main);
25 | }
26 |
27 | if (!entry) {
28 | entry = {};
29 | }
30 |
31 | const keys = Object.keys(flag).filter((name) => name !== 'main');
32 |
33 | for (const key of keys) {
34 | entry[key] = flag[key];
35 | }
36 | } else if (Array.isArray(flag)) {
37 | assertArray();
38 |
39 | entry.main = entry.main.concat(flag);
40 | } else if (typeof flag === 'string') {
41 | if (entry && entry.main) {
42 | assertArray();
43 |
44 | entry.main.push(flag);
45 | } else {
46 | entry = { main: flag };
47 | }
48 | }
49 | }
50 |
51 | return entry;
52 | };
53 |
--------------------------------------------------------------------------------
/lib/flags/resolver.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 | const isObject = require('isobject');
3 | const merge = require('merge-options');
4 |
5 | module.exports = {
6 | apply(argv, options) {
7 | const result = {};
8 | const resolve = {};
9 |
10 | if (argv.resolveAlias && isObject(argv.resolveAlias)) {
11 | resolve.alias = argv.resolveAlias;
12 | }
13 |
14 | if (argv.resolveExtensions) {
15 | const value = argv.resolveExtensions;
16 |
17 | if (value) {
18 | resolve.extensions = Array.isArray(value) ? value : value.split(/,\s*/);
19 | }
20 | }
21 |
22 | if (argv.resolveLoaderAlias) {
23 | result.resolveLoader = argv.resolveAlias;
24 | }
25 |
26 | if (Object.keys(resolve).length) {
27 | result.resolve = resolve;
28 | }
29 |
30 | return merge(options, result);
31 | },
32 |
33 | flags: {
34 | 'resolve-alias': {
35 | desc: chalk`Setup a module alias for resolving
36 | {dim e.g. --resolve-alias.jquery jquery.plugin}`,
37 | type: 'object',
38 | },
39 | 'resolve-extensions': {
40 | desc: chalk`Setup extensions that should be used to resolve modules
41 | {dim e.g. .es6,.js}`,
42 | type: ['string', 'array'],
43 | },
44 | 'resolve-loader-alias': {
45 | desc: 'Setup a loader alias for resolving',
46 | type: 'object',
47 | },
48 | },
49 |
50 | name: 'Resolver',
51 | };
52 |
--------------------------------------------------------------------------------
/lib/reporters/Reporter.js:
--------------------------------------------------------------------------------
1 | module.exports = class Reporter {
2 | /**
3 | @constructor
4 | @param compiler {Object} A webpack Compiler instance https://webpack.js.org/api/node/#compiler-instance
5 | */
6 | // eslint-disable-next-line no-unused-vars
7 | constructor(options) {
8 | this.compiler = options.compiler;
9 | this.config = options.config;
10 | }
11 |
12 | /**
13 | NOTE: Reporters also support a progress handler, which is called when webpack
14 | reports progress on a build, typically in tandem with the --progress CLI flag.
15 |
16 | @method progress
17 | @param data {Object} An object containing data on the current progress state of a build.
18 |
19 | const data = {
20 | profile: Boolean,
21 | fileName: String,
22 | scope: String,
23 | step: {
24 | index: Number,
25 | modulePosition: Number,
26 | name: String,
27 | percentage: Number,
28 | state: String,
29 | totalModules: Number,
30 | },
31 | };
32 | */
33 | // eslint-disable-next-line no-unused-vars
34 | progress(data) {}
35 |
36 | /**
37 | @method render
38 | @param error {Error} An Error object
39 | @param stats {Object} A webpack stats object https://webpack.js.org/api/node/#stats-object
40 | */
41 | // eslint-disable-next-line no-unused-vars
42 | render(error, stats) {}
43 | };
44 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable global-require, import/no-dynamic-require */
2 | // TODO: move the output from /dist to test/dist and update .gitignore
3 |
4 | const { join, resolve } = require('path');
5 |
6 | const { register } = require('../lib/global');
7 |
8 | register();
9 |
10 | global.expect = require('expect');
11 |
12 | global.resolve = resolve;
13 | global.fixture = (path) => require(resolve(__dirname, './fixtures', path));
14 | global.fixturePath = (path) => join(__dirname, './fixtures', path);
15 |
16 | require('./snapshot');
17 |
18 | require('./tests/commands/command');
19 | require('./tests/commands/help');
20 | require('./tests/commands/teach');
21 |
22 | require('./tests/cli');
23 | require('./tests/config');
24 | require('./tests/flags');
25 | require('./tests/progress');
26 | require('./tests/reporters');
27 |
28 | const flags = [
29 | 'bail',
30 | 'cache',
31 | 'config',
32 | 'config-name',
33 | 'context',
34 | 'debug',
35 | 'define',
36 | 'devtool',
37 | 'entry',
38 | 'hot',
39 | 'mode',
40 | 'module-bind',
41 | 'optimize',
42 | 'output',
43 | 'plugin',
44 | 'prefetch',
45 | 'profile',
46 | 'progress',
47 | 'provide',
48 | 'records',
49 | 'reporter',
50 | 'resolve',
51 | 'run-mode',
52 | 'target',
53 | 'watch',
54 | ];
55 |
56 | describe('Flags', () => {
57 | for (const test of flags) {
58 | require(`./tests/flags/${test}`);
59 | }
60 | });
61 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/plugin.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --plugin > should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-a.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | UglifyJsPlugin {
9 | "options": Object {
10 | "cache": false,
11 | "exclude": undefined,
12 | "extractComments": false,
13 | "include": undefined,
14 | "parallel": false,
15 | "sourceMap": false,
16 | "test": /\\\\\\.js\\(\\\\\\?\\.\\*\\)\\?\\$/i,
17 | "uglifyOptions": Object {
18 | "compress": Object {
19 | "inline": 1,
20 | },
21 | "output": Object {
22 | "comments": /\\^\\\\\\*\\*!\\|@preserve\\|@license\\|@cc_on/,
23 | },
24 | },
25 | "warningsFilter": [Function],
26 | },
27 | },
28 | NamedModulesPlugin {
29 | "options": Object {},
30 | },
31 | ],
32 | "reporter": "/test/fixtures/common/test-reporter.js",
33 | }
34 | `;
35 |
36 | exports[`Flags > --plugin > should build #0 1`] = `
37 | "Version: webpack 4.14.0
38 | Asset Size Chunks Chunk Names
39 | main.js 1.27 KiB main [emitted] main
40 | Entrypoint main = main.js
41 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
42 | `;
43 |
44 | exports[`Flags > --plugin > should build #1 1`] = `"406b140a"`;
45 |
--------------------------------------------------------------------------------
/lib/commands/HelpCommand.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 | const open = require('opn');
3 |
4 | const pkg = require('../../package.json');
5 |
6 | const Command = require('./Command');
7 |
8 | class HelpCommandError extends Command.CommandError {
9 | constructor(...args) {
10 | super(...args);
11 | this.name = 'HelpCommandError';
12 | }
13 | }
14 |
15 | module.exports = class HelpCommand extends Command {
16 | help() {
17 | return chalk`
18 | {blue help} v${pkg.version}
19 |
20 | Displays help for a given installed webpack command.
21 |
22 | {underline Usage}
23 | $ webpack help
24 |
25 | {underline Examples}
26 | $ webpack help
27 | $ webpack help init
28 | $ webpack help serve
29 | `;
30 | }
31 |
32 | // eslint-disable-next-line consistent-return
33 | run(cli, options = {}) {
34 | const { log } = console;
35 | const [, target] = cli.input;
36 |
37 | /* istanbul ignore if */
38 | if (!target) {
39 | open('https://webpack.js.org/');
40 | return '';
41 | }
42 |
43 | const command = cli.commands[target];
44 |
45 | if (!command) {
46 | throw new HelpCommandError(
47 | `The command '${target}' has not been installed`
48 | );
49 | }
50 |
51 | if (options.stdout === false) {
52 | return command.help();
53 | }
54 |
55 | /* istanbul ignore next */
56 | log(command.help());
57 | }
58 | };
59 |
60 | module.exports.HelpCommandError = HelpCommandError;
61 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/BUG.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🐛 Bug Report
3 | about: Something went awry and you'd like to tell us about it.
4 |
5 | ---
6 |
7 |
17 |
18 | * Operating System:
19 | * Node Version:
20 | * NPM Version:
21 | * webpack Version:
22 | * webpack-command Version:
23 |
24 | ### CLI Command
25 |
26 | ```console
27 | $ wp ... # remove this block if using the API
28 | ```
29 |
30 | ### Expected Behavior
31 |
32 |
33 |
34 | ### Actual Behavior
35 |
36 |
37 |
38 | ### Code
39 |
40 | ```js
41 | // webpack.config.js
42 | // If your bitchin' code blocks are over 20 lines, please paste a link to a gist
43 | // (https://gist.github.com).
44 | ```
45 |
46 | ```js
47 | // additional code, HEY YO remove this block if you don't need it
48 | ```
49 |
50 | ### How Do We Reproduce?
51 |
52 |
--------------------------------------------------------------------------------
/lib/reporters/BasicReporter.js:
--------------------------------------------------------------------------------
1 | const ora = require('ora');
2 |
3 | const Reporter = require('./Reporter');
4 |
5 | module.exports = class BasicReporter extends Reporter {
6 | constructor(...args) {
7 | super(...args);
8 |
9 | this.spinner = ora({ spinner: 'toggle6' });
10 | }
11 |
12 | // TODO: create proper testing for this with a large build an stdout hooks.
13 | /* istanbul ignore next */
14 | progress(data) {
15 | if (!this.spinner.isSpinning && data.step.percentage < 1) {
16 | this.spinner.start(data.step.name);
17 | }
18 |
19 | const { name, modulePosition, totalModules } = data.step;
20 | const percent = Math.floor(data.step.percentage * 100);
21 |
22 | if (modulePosition) {
23 | this.spinner.text = `${percent}% ${modulePosition}/${totalModules} ${name} ${
24 | data.fileName
25 | }`;
26 | } else {
27 | this.spinner.text = `${percent} ${name} ${data.scope}`;
28 | }
29 |
30 | if (data.step.percentage >= 1) {
31 | this.spinner.stop();
32 | }
33 | }
34 |
35 | render(error, stats) {
36 | const { log } = console;
37 |
38 | if (error) {
39 | return error;
40 | }
41 |
42 | const compilers = this.compiler.compilers || [this.compiler];
43 |
44 | const targetCompiler = compilers.find((comp) => !!comp.options.stats);
45 | const { options } = targetCompiler || { options: {} };
46 | const result = stats.toString(options.stats);
47 |
48 | log(result);
49 |
50 | return result;
51 | }
52 | };
53 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/mode.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --mode > dev should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-a.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | NamedModulesPlugin {
9 | "options": Object {},
10 | },
11 | ],
12 | "reporter": "/test/fixtures/common/test-reporter.js",
13 | }
14 | `;
15 |
16 | exports[`Flags > --mode > dev should build #0 1`] = `
17 | "Version: webpack 4.14.0
18 | Asset Size Chunks Chunk Names
19 | main.js 3.92 KiB main [emitted] main
20 | Entrypoint main = main.js
21 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
22 | `;
23 |
24 | exports[`Flags > --mode > dev should build #1 1`] = `"1c77bf93"`;
25 |
26 | exports[`Flags > --mode > prod should apply #0 1`] = `
27 | Object {
28 | "entry": "/test/fixtures/common/entry-a.js",
29 | "mode": "production",
30 | "plugins": Array [
31 | NamedModulesPlugin {
32 | "options": Object {},
33 | },
34 | ],
35 | "reporter": "/test/fixtures/common/test-reporter.js",
36 | }
37 | `;
38 |
39 | exports[`Flags > --mode > prod should build #0 1`] = `
40 | "Version: webpack 4.14.0
41 | Asset Size Chunks Chunk Names
42 | main.js 1 KiB 0 [emitted] main
43 | Entrypoint main = main.js
44 | [./test/fixtures/common/entry-a.js] 41 bytes {0} [built]"
45 | `;
46 |
47 | exports[`Flags > --mode > prod should build #1 1`] = `"6cf29bc5"`;
48 |
--------------------------------------------------------------------------------
/test/tests/flags/watch.js:
--------------------------------------------------------------------------------
1 | const { apply, test, validate } = require('../../util');
2 |
3 | test('--watch', module, () => {
4 | const fixture = 'watch/single-flag';
5 | const opts = { fixture };
6 |
7 | let config;
8 |
9 | it(`should validate`, () => {
10 | expect(validate(opts)).toEqual(true);
11 | });
12 |
13 | it(`should apply`, () => {
14 | config = apply(opts);
15 |
16 | expect(config).toMatchSnapshot();
17 | });
18 | });
19 |
20 | test('--watch-aggregate-timeout', module, () => {
21 | const fixture = 'watch/watch-aggregate-timeout';
22 | const opts = { fixture };
23 |
24 | let config;
25 |
26 | it(`should validate`, () => {
27 | expect(validate(opts)).toEqual(true);
28 | });
29 |
30 | it(`should apply`, () => {
31 | config = apply(opts);
32 |
33 | expect(config).toMatchSnapshot();
34 | });
35 | });
36 |
37 | test('--watch-poll', module, () => {
38 | const fixture = 'watch/watch-poll';
39 | const opts = { fixture };
40 |
41 | let config;
42 |
43 | it(`should validate`, () => {
44 | expect(validate(opts)).toEqual(true);
45 | });
46 |
47 | it(`should apply`, () => {
48 | config = apply(opts);
49 |
50 | expect(config).toMatchSnapshot();
51 | });
52 | });
53 |
54 | test('--watch-stdin', module, () => {
55 | const fixture = 'watch/watch-stdin';
56 | const opts = { fixture };
57 |
58 | let config;
59 |
60 | it(`should validate`, () => {
61 | expect(validate(opts)).toEqual(true);
62 | });
63 |
64 | it(`should apply`, () => {
65 | config = apply(opts);
66 |
67 | expect(config).toMatchSnapshot();
68 | });
69 | });
70 |
--------------------------------------------------------------------------------
/lib/flags/optimization.js:
--------------------------------------------------------------------------------
1 | const camelcase = require('camelcase');
2 | const merge = require('merge-options');
3 | const { LoaderOptionsPlugin, optimize } = require('webpack');
4 |
5 | const { MinChunkSizePlugin, LimitChunkCountPlugin } = optimize;
6 |
7 | module.exports = {
8 | apply(argv, options) {
9 | let plugins = [];
10 |
11 | if (options.plugins) {
12 | plugins = plugins.concat(options.plugins);
13 | }
14 |
15 | const { flags } = module.exports;
16 | const keys = Object.keys(flags);
17 |
18 | for (const key of keys) {
19 | const arg = camelcase(key);
20 | const flag = flags[key];
21 | const value = argv[arg];
22 |
23 | if (value) {
24 | const plugin = flag.apply(value);
25 | plugins.unshift(plugin);
26 | }
27 | }
28 |
29 | return merge(options, plugins.length ? { plugins } : {});
30 | },
31 |
32 | flags: {
33 | 'optimize-max-chunks': {
34 | apply: (value) =>
35 | new LimitChunkCountPlugin({ maxChunks: parseInt(value, 10) }),
36 | desc: 'Try to keep the chunk count below a limit',
37 | type: 'number',
38 | },
39 | 'optimize-min-chunk-size': {
40 | apply: (value) =>
41 | new MinChunkSizePlugin({ minChunkSize: parseInt(value, 10) }),
42 | desc: 'Try to keep the chunk size above a limit',
43 | type: 'number',
44 | },
45 | 'optimize-minimize': {
46 | apply: () => new LoaderOptionsPlugin({ minimize: true }),
47 | desc: 'Minimize javascript and switches loaders to minimizing',
48 | type: 'boolean',
49 | },
50 | },
51 |
52 | name: 'Optimization',
53 | };
54 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/run-mode.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --run-dev > should apply #0 1`] = `
4 | Object {
5 | "devtool": "eval-cheap-module-source-map",
6 | "entry": "/test/fixtures/common/entry-a.js",
7 | "mode": "development",
8 | "plugins": Array [
9 | LoaderOptionsPlugin {
10 | "options": Object {
11 | "debug": true,
12 | "test": Object {
13 | "test": [Function],
14 | },
15 | },
16 | },
17 | NamedModulesPlugin {
18 | "options": Object {},
19 | },
20 | ],
21 | "reporter": "/test/fixtures/common/test-reporter.js",
22 | }
23 | `;
24 |
25 | exports[`Flags > --run-dev > should build #0 1`] = `
26 | "Version: webpack 4.14.0
27 | Asset Size Chunks Chunk Names
28 | main.js 4.32 KiB main [emitted] main
29 | Entrypoint main = main.js
30 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
31 | `;
32 |
33 | exports[`Flags > --run-dev > should build #1 1`] = `"39241717"`;
34 |
35 | exports[`Flags > --run-prod > should apply #0 1`] = `
36 | Object {
37 | "entry": "/test/fixtures/common/entry-a.js",
38 | "mode": "development",
39 | "plugins": Array [
40 | NamedModulesPlugin {
41 | "options": Object {},
42 | },
43 | ],
44 | "reporter": "/test/fixtures/common/test-reporter.js",
45 | }
46 | `;
47 |
48 | exports[`Flags > --run-prod > should build #0 1`] = `
49 | "Version: webpack 4.14.0
50 | Asset Size Chunks Chunk Names
51 | main.js 3.92 KiB main [emitted] main
52 | Entrypoint main = main.js
53 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
54 | `;
55 |
56 | exports[`Flags > --run-prod > should build #1 1`] = `"1c77bf93"`;
57 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/records.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --records-* > input-output should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-a.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | NamedModulesPlugin {
9 | "options": Object {},
10 | },
11 | ],
12 | "recordsInputPath": "/dist/records-input.json",
13 | "recordsOutputPath": "/dist/records-output.json",
14 | "reporter": "/test/fixtures/common/test-reporter.js",
15 | }
16 | `;
17 |
18 | exports[`Flags > --records-* > input-output should build #0 1`] = `
19 | "Version: webpack 4.14.0
20 | Asset Size Chunks Chunk Names
21 | main.js 3.92 KiB main [emitted] main
22 | Entrypoint main = main.js
23 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
24 | `;
25 |
26 | exports[`Flags > --records-* > input-output should build #1 1`] = `"1c77bf93"`;
27 |
28 | exports[`Flags > --records-* > path should apply #0 1`] = `
29 | Object {
30 | "entry": "/test/fixtures/common/entry-a.js",
31 | "mode": "development",
32 | "plugins": Array [
33 | NamedModulesPlugin {
34 | "options": Object {},
35 | },
36 | ],
37 | "recordsPath": "/dist/records.json",
38 | "reporter": "/test/fixtures/common/test-reporter.js",
39 | }
40 | `;
41 |
42 | exports[`Flags > --records-* > path should build #0 1`] = `
43 | "Version: webpack 4.14.0
44 | Asset Size Chunks Chunk Names
45 | main.js 3.92 KiB main [emitted] main
46 | Entrypoint main = main.js
47 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
48 | `;
49 |
50 | exports[`Flags > --records-* > path should build #1 1`] = `"1c77bf93"`;
51 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/watch.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --watch > should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-a.js",
6 | "mode": "development",
7 | "name": "single-flag",
8 | "plugins": Array [
9 | NamedModulesPlugin {
10 | "options": Object {},
11 | },
12 | ],
13 | "reporter": "/test/fixtures/common/test-reporter.js",
14 | "watch": true,
15 | }
16 | `;
17 |
18 | exports[`Flags > --watch-aggregate-timeout > should apply #0 1`] = `
19 | Object {
20 | "entry": "/test/fixtures/common/entry-a.js",
21 | "mode": "development",
22 | "plugins": Array [
23 | NamedModulesPlugin {
24 | "options": Object {},
25 | },
26 | ],
27 | "reporter": "/test/fixtures/common/test-reporter.js",
28 | "watchOptions": Object {
29 | "aggregateTimeout": 400,
30 | },
31 | }
32 | `;
33 |
34 | exports[`Flags > --watch-poll > should apply #0 1`] = `
35 | Object {
36 | "entry": "/test/fixtures/common/entry-a.js",
37 | "mode": "development",
38 | "plugins": Array [
39 | NamedModulesPlugin {
40 | "options": Object {},
41 | },
42 | ],
43 | "reporter": "/test/fixtures/common/test-reporter.js",
44 | "watchOptions": Object {
45 | "poll": 1000,
46 | },
47 | }
48 | `;
49 |
50 | exports[`Flags > --watch-stdin > should apply #0 1`] = `
51 | Object {
52 | "entry": "/test/fixtures/common/entry-a.js",
53 | "mode": "development",
54 | "plugins": Array [
55 | NamedModulesPlugin {
56 | "options": Object {},
57 | },
58 | ],
59 | "reporter": "/test/fixtures/common/test-reporter.js",
60 | "watch": true,
61 | "watchOptions": Object {
62 | "stdin": true,
63 | },
64 | }
65 | `;
66 |
--------------------------------------------------------------------------------
/lib/progress.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 |
3 | const { ProgressPlugin } = webpack;
4 |
5 | function parseArgs(profile, ...args) {
6 | // args is an unorganized set of parameters.
7 | // e.g. building modules|5/6 modules|1 active|/node_modules/lodash/lodash.js
8 | // building modules|14/14 modules|0 active|
9 | // finish module graph
10 | // finish module graph|FlagDependencyExportsPlugin
11 | const [value, , counts, index, fileName] = args;
12 | const [, modulePos, totalModules] = (
13 | (counts || '').match(/(\d+)\/(\d+)/) || []
14 | ).map((match) => parseInt(match, 10));
15 | const [, indexNumber, indexState] = (index || '').match(/(\d+)\s(.+)/) || [];
16 | const percentage = parseFloat(value);
17 | const [, stepName] = args;
18 | let scope;
19 | let empty;
20 |
21 | // we've got a step with a scope on our hands
22 | // e.g. finish module graph|FlagDependencyExportsPlugin
23 | if (args.length === 3) {
24 | scope = counts;
25 | }
26 |
27 | const result = {
28 | profile,
29 | fileName,
30 | scope,
31 | step: {
32 | index: parseInt(indexNumber, 10) || empty,
33 | modulePosition: modulePos || empty,
34 | name: stepName,
35 | percentage: percentage || empty,
36 | state: indexState,
37 | totalModules: totalModules || empty,
38 | },
39 | };
40 |
41 | return result;
42 | }
43 |
44 | module.exports = {
45 | apply(config, compiler, reporter) {
46 | const { profile } = config;
47 | const opts = { profile };
48 |
49 | if (reporter.progress) {
50 | opts.handler = (...args) => {
51 | const data = parseArgs(profile, ...args);
52 | reporter.progress(data);
53 | };
54 | }
55 |
56 | const plugin = new ProgressPlugin(opts);
57 | plugin.apply(compiler);
58 | },
59 |
60 | parseArgs,
61 | };
62 |
--------------------------------------------------------------------------------
/test/tests/commands/help.js:
--------------------------------------------------------------------------------
1 | const { test } = require('../../util');
2 | const HelpCommand = require('../../../lib/commands/HelpCommand');
3 | const {
4 | help: commandHelp,
5 | load: getCommands,
6 | } = require('../../../lib/commands/');
7 |
8 | let command;
9 | const commands = getCommands();
10 | const { HelpCommandError } = HelpCommand;
11 |
12 | test('help command', module, () => {
13 | it(`should instantiate`, () => {
14 | command = new HelpCommand();
15 | expect(command).toBeInstanceOf(HelpCommand);
16 | });
17 |
18 | it(`should display help`, () => {
19 | let result = command.help();
20 | result = result.replace(/\d+\.\d+\.\d+/, '');
21 | expect(result).toMatchSnapshot();
22 | });
23 |
24 | it(`should display all commands`, () => {
25 | const result = commandHelp();
26 | expect(result).toMatchSnapshot();
27 | });
28 |
29 | it(`should display help for the help command`, () => {
30 | const cli = {
31 | commands,
32 | input: ['help', 'help'],
33 | };
34 | const stdout = false;
35 | let result = command.run(cli, { stdout });
36 | result = result.replace(/\d+\.\d+\.\d+/, '');
37 |
38 | expect(result).toMatchSnapshot();
39 | });
40 |
41 | it(`should display help for the teach command`, () => {
42 | const cli = {
43 | commands,
44 | input: ['help', 'teach'],
45 | };
46 | const stdout = false;
47 | let result = command.run(cli, { stdout });
48 | result = result.replace(/\d+\.\d+\.\d+/, '');
49 |
50 | expect(result).toMatchSnapshot();
51 | });
52 |
53 | it(`should throw for unknown command`, () => {
54 | const cli = {
55 | commands,
56 | input: ['help', 'unknown'],
57 | };
58 | const stub = () => command.run(cli);
59 |
60 | expect(stub).toThrow(HelpCommandError);
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/docs/TeachCommand.md:
--------------------------------------------------------------------------------
1 | # Teach Command
2 |
3 | 🍎 Teaches `webpack-command` that a command has been installed and is available.
4 |
5 | ```console
6 | $ webpack teach [...options]
7 |
8 | Usage
9 | $ webpack teach --command --module
10 |
11 | Options
12 | --command The name of a command that users will type
13 | --forget Instructs the tool to forget a previously added command
14 | --module The npm module name of a command
15 |
16 | Examples
17 | $ webpack teach --command init --module webpack-command-init
18 | $ webpack teach --command init --forget
19 | ```
20 |
21 | ## Getting Started
22 |
23 | > This command is included by default with `webpack-command`
24 |
25 | ## Usage
26 |
27 | To teach `webpack-command` that a command package has been installed run:
28 |
29 | ```console
30 | $ webpack teach --command --module
31 | ```
32 |
33 | _Note: `` can be either an npm package name or an absolute path to
34 | a module file._
35 |
36 | To teach `webpack-command` that a command package should be forgotten run:
37 |
38 | ```console
39 | $ webpack teach --command --forget
40 | ```
41 |
42 | ## When to Use
43 |
44 | This command is primarily meant to be used in the `postinstall` and
45 | `postuninstall` npm scripts for an npm package, but can be used for specialized
46 | local command modules for devops environments.
47 |
48 | An npm `package.json` example:
49 |
50 | ```json
51 | {
52 | "scripts": {
53 | "postinstall": "webpack teach --command batman --module webpack-command-batman",
54 | "postuninstall": "webpack teach --command batman --forget"
55 | }
56 | }
57 | ```
58 |
59 | The example above teaches `webpack-command` that it should recognize `batman` as
60 | a valid command, and use the `webpack-command-batman` module to run it.
61 |
62 | ## That's All, Folks
--------------------------------------------------------------------------------
/lib/config.js:
--------------------------------------------------------------------------------
1 | const { isAbsolute, resolve } = require('path');
2 |
3 | const loader = require('@webpack-contrib/config-loader');
4 | const merge = require('merge-options').bind({ concatArrays: true });
5 |
6 | const WebpackCommandError = require('./WebpackCommandError');
7 |
8 | module.exports = {
9 | distill(argv, config, options) {
10 | const cwdContext = { context: process.cwd() };
11 | let result;
12 |
13 | if (Array.isArray(config)) {
14 | result = config.map((conf) => merge(cwdContext, conf, options));
15 | } else {
16 | result = merge(cwdContext, config, options);
17 | }
18 |
19 | if (argv.configName) {
20 | if (Array.isArray(config)) {
21 | const found = config.find((conf) => conf.name === argv.configName);
22 |
23 | if (!found) {
24 | throw new WebpackCommandError(
25 | `The --config-name specified was not found`
26 | );
27 | }
28 |
29 | result = found;
30 | } else {
31 | throw new WebpackCommandError(
32 | '--config-name was used but the specified configuration is not an Array'
33 | );
34 | }
35 | }
36 |
37 | return result;
38 | },
39 |
40 | load(argv, options) {
41 | const loaderOptions = {
42 | allowMissing: true,
43 | configPath: argv.config,
44 | require: argv.require,
45 | };
46 |
47 | if (argv.config) {
48 | if (isAbsolute(argv.config)) {
49 | loaderOptions.configPath = argv.config;
50 | } else {
51 | loaderOptions.configPath = resolve(process.cwd(), argv.config);
52 | }
53 | }
54 |
55 | return loader(loaderOptions).then((result) => {
56 | const { config } = result;
57 | const { distill } = module.exports;
58 | const target = distill(argv, config, options);
59 |
60 | return target;
61 | });
62 | },
63 | };
64 |
--------------------------------------------------------------------------------
/test/tests/progress.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 |
3 | const progress = require('../../lib/progress');
4 | const { test } = require('../util');
5 |
6 | test('progress util', module, () => {
7 | // e.g. building modules|5/6 modules|1 active|/node_modules/lodash/lodash.js
8 | // building modules|14/14 modules|0 active|
9 | // finish module graph
10 | // finish module graph|FlagDependencyExportsPlugin
11 |
12 | it('should parse args: all args', () => {
13 | const args = [
14 | false,
15 | '0.1',
16 | 'building modules',
17 | '5/6 modules',
18 | '1 active',
19 | '/node_modules/lodash/lodash.js',
20 | ];
21 | const result = progress.parseArgs(...args);
22 |
23 | expect(result).toMatchSnapshot();
24 | });
25 |
26 | it('should parse args: no filename', () => {
27 | const args = [false, '0.1', 'building modules', '5/6 modules', '1 active'];
28 | const result = progress.parseArgs(...args);
29 |
30 | expect(result).toMatchSnapshot();
31 | });
32 |
33 | it('should parse args: only step name', () => {
34 | const args = [false, '0.1', 'finish module graph'];
35 | const result = progress.parseArgs(...args);
36 |
37 | expect(result).toMatchSnapshot();
38 | });
39 |
40 | it('should parse args: step name and scope', () => {
41 | const args = [
42 | false,
43 | '0.1',
44 | 'finish module graph',
45 | 'FlagDependencyExportsPlugin',
46 | ];
47 | const result = progress.parseArgs(...args);
48 |
49 | expect(result).toMatchSnapshot();
50 | });
51 |
52 | it('should apply', () => {
53 | const config = { profile: false };
54 | const compiler = webpack({});
55 | const reporter = { progress: () => {} };
56 | progress.apply(config, compiler, reporter);
57 |
58 | expect(compiler.hooks.compilation.taps).toMatchSnapshot();
59 | });
60 | });
61 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Welcome!
2 | :heart: Thanks for your interest and time in contributing to this project.
3 |
4 | ## What We Use
5 |
6 | - Building: [Webpack](https://webpack.js.org)
7 | - Linting: [ESLint](http://eslint.org/)
8 | - NPM: [NPM as a Build Tool](https://css-tricks.com/using-npm-build-tool/)
9 | - Testing: [Mocha](https://mochajs.org)
10 |
11 | ## Forking and Cloning
12 |
13 | You'll need to first fork this repository, and then clone it locally before you
14 | can submit a Pull Request with your proposed changes.
15 |
16 | Please see the following articles for help getting started with git:
17 |
18 | [Forking a Repository](https://help.github.com/articles/fork-a-repo/)
19 | [Cloning a Repository](https://help.github.com/articles/cloning-a-repository/)
20 |
21 | ## Pull Requests
22 |
23 | Please lint and test your changes before submitting a Pull Request. You can lint your
24 | changes by running:
25 |
26 | ```console
27 | $ npm run lint
28 | ```
29 |
30 | You can test your changes against the test suite for this module by running:
31 |
32 | ```console
33 | $ npm run test
34 | ```
35 |
36 | _Note: Please avoid committing `package-lock.json` files!_
37 |
38 | Please don't change variable or parameter names to match your personal
39 | preferences, unless the change is part of a refactor or significant modification
40 | of the codebase (which is very rare).
41 |
42 | Please remember to thoroughly explain your Pull Request if it doesn't have an
43 | associated issue. If you're changing code significantly, please remember to add
44 | inline or block comments in the code as appropriate.
45 |
46 | ## Testing Your Pull Request
47 |
48 | You may have the need to test your changes in a real-world project or dependent
49 | module. Thankfully, Github provides a means to do this. Add a dependency to the
50 | `package.json` for such a project as follows:
51 |
52 | ```json
53 | "webpack-serve": "webpack-contrib/webpack-serve#{id}/head"
54 | ```
55 |
56 | Where `{id}` is the # ID of your Pull Request.
57 |
58 | ## Thanks
59 |
60 | For your interest, time, understanding, and for following this simple guide.
61 |
--------------------------------------------------------------------------------
/test/snapshot.js:
--------------------------------------------------------------------------------
1 | const {
2 | addSerializer,
3 | SnapshotState,
4 | toMatchSnapshot,
5 | toThrowErrorMatchingSnapshot,
6 | } = require('jest-snapshot');
7 | const serializer = require('jest-serializer-path');
8 | const minimist = require('minimist');
9 |
10 | const argv = minimist(process.argv.slice(2));
11 |
12 | let current = null;
13 | const cache = {};
14 |
15 | global.beforeEach(function beforeEach() {
16 | current = this.currentTest;
17 | });
18 |
19 | function nameTest(test) {
20 | let next = test;
21 | const title = [];
22 |
23 | for (;;) {
24 | if (!next.parent) {
25 | break;
26 | }
27 |
28 | title.push(next.title);
29 | next = next.parent;
30 | }
31 |
32 | let result = title.reverse().join(' > ');
33 | let index = 0;
34 |
35 | // can't yet figure out how jest-snapshot figures out how many snapshots are
36 | // in a single test/it() group, so we'll mimic it for the time being.
37 | if (typeof cache[result] !== 'undefined') {
38 | cache[result] += 1;
39 | index = cache[result];
40 | } else {
41 | cache[result] = 0;
42 | }
43 |
44 | result = `${result} #${index}`;
45 |
46 | return result;
47 | }
48 |
49 | function match(received) {
50 | const { file } = current;
51 | const snapshotState = new SnapshotState(file, {
52 | updateSnapshot: argv.update || argv.u ? 'all' : 'new',
53 | });
54 | const matcher = toMatchSnapshot.bind({
55 | snapshotState,
56 | currentTestName: nameTest(current),
57 | });
58 |
59 | const result = matcher(received);
60 |
61 | snapshotState.save();
62 |
63 | return result;
64 | }
65 |
66 | function matchError(received) {
67 | const { file } = current;
68 | const snapshotState = new SnapshotState(file, {
69 | updateSnapshot: argv.update ? 'all' : 'new',
70 | });
71 | const matcher = toThrowErrorMatchingSnapshot.bind({
72 | snapshotState,
73 | currentTestName: nameTest(current),
74 | });
75 |
76 | const result = matcher(received);
77 |
78 | snapshotState.save();
79 |
80 | return result;
81 | }
82 |
83 | addSerializer(serializer);
84 |
85 | expect.extend({
86 | toMatchSnapshot: match,
87 | toThrowErrorMatchingSnapshot: matchError,
88 | });
89 |
--------------------------------------------------------------------------------
/test/tests/commands/teach.js:
--------------------------------------------------------------------------------
1 | const { readFileSync: read } = require('fs');
2 |
3 | const { test } = require('../../util');
4 |
5 | const TeachCommand = require('../../../lib/commands/TeachCommand');
6 |
7 | const dataFilePath = resolve('./data/commands.json');
8 | const testCommandPath = resolve('./test/fixtures/commands/TestCommand.js');
9 |
10 | const { TeachCommandError } = TeachCommand;
11 | const command = new TeachCommand();
12 |
13 | test('teach command', module, () => {
14 | it('should throw for no args', () => {
15 | const stub = () => command.run({ flags: {} });
16 |
17 | expect(stub).toThrowErrorMatchingSnapshot(TeachCommandError);
18 | });
19 |
20 | it('should throw for no --command value', () => {
21 | const flags = { command: true };
22 | const stub = () => command.run({ flags });
23 |
24 | expect(stub).toThrowErrorMatchingSnapshot(TeachCommandError);
25 | });
26 |
27 | it('should throw for no --module', () => {
28 | const flags = { command: 'test' };
29 | const stub = () => command.run({ flags });
30 |
31 | expect(stub).toThrowErrorMatchingSnapshot(TeachCommandError);
32 | });
33 |
34 | it('should throw for no --module value', () => {
35 | const flags = { command: 'test', module: true };
36 | const stub = () => command.run({ flags });
37 |
38 | expect(stub).toThrowErrorMatchingSnapshot(TeachCommandError);
39 | });
40 |
41 | it('should throw for missing --module', () => {
42 | const flags = { command: 'test', module: 'missing-module' };
43 | const stub = () => command.run({ flags });
44 |
45 | expect(stub).toThrowErrorMatchingSnapshot(TeachCommandError);
46 | });
47 |
48 | it('should learn module', () => {
49 | const flags = { command: 'test', module: testCommandPath };
50 | command.run({ flags });
51 |
52 | expect(read(dataFilePath, 'utf-8')).toMatchSnapshot();
53 | });
54 |
55 | it('should throw for duplicate modules', () => {
56 | const flags = { command: 'test', module: testCommandPath };
57 | const stub = () => command.run({ flags });
58 |
59 | expect(stub).toThrowErrorMatchingSnapshot(TeachCommandError);
60 | });
61 |
62 | it('should forget module', () => {
63 | const flags = { command: 'test', forget: true };
64 | command.run({ flags });
65 |
66 | expect(read(dataFilePath, 'utf-8')).toMatchSnapshot();
67 | });
68 | });
69 |
--------------------------------------------------------------------------------
/test/tests/config.js:
--------------------------------------------------------------------------------
1 | const { test } = require('../util');
2 | const { distill } = require('../../lib/config');
3 | const { apply } = require('../../lib/flags');
4 |
5 | const config = [
6 | {
7 | entry: resolve(__dirname, '../../common/entry-a.js'),
8 | mode: 'development',
9 | },
10 | {
11 | entry: resolve(__dirname, '../../common/entry-b.js'),
12 | mode: 'development',
13 | },
14 | ];
15 |
16 | test('lib/config', module, () => {
17 | it(`distill()`, () => {
18 | const result = distill({}, config, {});
19 | expect(result).toMatchSnapshot();
20 | });
21 |
22 | it(`distill() context`, () => {
23 | const argv = {};
24 | const options = apply({}, {});
25 |
26 | let result = distill(argv, { context: 'batman' }, { context: 'superman' });
27 | expect(result.context).toBe('superman');
28 |
29 | result = distill(argv, { context: 'batman' }, options);
30 | expect(result.context).toBe('batman');
31 |
32 | result = distill(argv, {}, options);
33 | expect(result.context).toBe(process.cwd());
34 | });
35 |
36 | it(`distill() plugins`, () => {
37 | let result = distill({}, {}, { plugins: [1] });
38 | expect(result).toMatchSnapshot();
39 |
40 | result = distill({}, { plugins: [] }, { plugins: [1] });
41 | expect(result).toMatchSnapshot();
42 |
43 | result = distill({}, { plugins: [1] }, { plugins: [1] });
44 | expect(result).toMatchSnapshot();
45 | });
46 |
47 | it(`distill() plugins from config array`, () => {
48 | const conf = [].concat(config);
49 | let result = distill({}, conf, { plugins: [1] });
50 |
51 | expect(result).toMatchSnapshot();
52 |
53 | conf[0].plugins = [];
54 | result = distill({}, conf, { plugins: [1] });
55 |
56 | expect(result).toMatchSnapshot();
57 |
58 | conf[1].plugins = [1];
59 | result = distill({}, conf, { plugins: [1] });
60 |
61 | expect(result).toMatchSnapshot();
62 | });
63 |
64 | it(`distill() --config-name`, () => {
65 | config[1].name = 'test';
66 |
67 | const argv = { configName: 'test' };
68 | const result = distill(argv, config, {});
69 | expect(result).toMatchSnapshot();
70 |
71 | delete config[1].name;
72 | });
73 |
74 | it(`distill() --config-name not found`, () => {
75 | const argv = { configName: 'test' };
76 | const stub = () => distill(argv, config, {});
77 | expect(stub).toThrow();
78 | });
79 |
80 | it(`distill() --config-name not array`, () => {
81 | const argv = { configName: 'test' };
82 | const stub = () => distill(argv, config[0], {});
83 | expect(stub).toThrow();
84 | });
85 | });
86 |
--------------------------------------------------------------------------------
/test/tests/flags.js:
--------------------------------------------------------------------------------
1 | const { test } = require('../util');
2 | const flags = require('../../lib/flags');
3 | const { loadPlugin, validateFlags } = require('../../lib/flags/util');
4 |
5 | const config = require('../fixtures/common/webpack.config.js');
6 |
7 | test('lib/flags', module, () => {
8 | it(`should display help`, () => {
9 | const result = flags.help();
10 | expect(result).toMatchSnapshot();
11 | });
12 |
13 | it(`should return minimist opts`, () => {
14 | const result = flags.opts();
15 | expect(result).toMatchSnapshot();
16 | });
17 |
18 | it('should parse flags cleanly', () => {
19 | const result = flags.apply({}, {});
20 | expect(result).toMatchSnapshot();
21 | });
22 |
23 | it('should parse compound flags: --run-dev', () => {
24 | const result = flags.apply({ runDev: true }, config);
25 | expect(result).toMatchSnapshot();
26 | });
27 |
28 | it('should parse compound flags: --run-prod', () => {
29 | const result = flags.apply({ runProd: true }, config);
30 | expect(result).toMatchSnapshot();
31 | });
32 | });
33 |
34 | test('lib/flags/util', module, () => {
35 | const allFlags = flags.getFlags();
36 | const options = { stdout: false };
37 |
38 | it(`should validate flags`, () => {
39 | const argv = { debug: true, watch: true };
40 | const result = validateFlags(allFlags, argv, options);
41 | expect(result).toBe(true);
42 | });
43 |
44 | it(`should not allow invalid value types`, () => {
45 | const argv = { debug: 'yes' };
46 | try {
47 | validateFlags(allFlags, argv, options);
48 | } catch (e) {
49 | expect(e).toMatchSnapshot();
50 | }
51 | });
52 |
53 | it(`should suggest alternatives`, () => {
54 | const argv = { debg: true, wath: true };
55 | try {
56 | validateFlags(allFlags, argv, options);
57 | } catch (e) {
58 | expect(e).toMatchSnapshot();
59 | }
60 | });
61 |
62 | it('should load a plugin', () => {
63 | expect(loadPlugin('uglifyjs-webpack-plugin')).toMatchSnapshot();
64 | });
65 |
66 | it('should load a plugin with querystring', () => {
67 | expect(loadPlugin('uglifyjs-webpack-plugin?cache=true')).toMatchSnapshot();
68 | });
69 |
70 | it('should fail to load a plugin with bad querystring', () => {
71 | const fn = () => loadPlugin('uglifyjs-webpack-plugin?...');
72 | expect(fn).toThrowErrorMatchingSnapshot();
73 | });
74 |
75 | it('should fail to load a plugin with bad options', () => {
76 | const fn = () => loadPlugin('uglifyjs-webpack-plugin?true');
77 | expect(fn).toThrowErrorMatchingSnapshot();
78 | });
79 | });
80 |
--------------------------------------------------------------------------------
/lib/flags/output.js:
--------------------------------------------------------------------------------
1 | const { basename, dirname, isAbsolute, resolve } = require('path');
2 |
3 | const camelcase = require('camelcase');
4 | const merge = require('merge-options');
5 |
6 | module.exports = {
7 | apply(argv, options) {
8 | const output = {};
9 | const { flags } = module.exports;
10 | const keys = Object.keys(flags).filter((key) => key !== 'output');
11 |
12 | if (argv.output) {
13 | let outputPath = argv.output;
14 | if (!isAbsolute(outputPath)) {
15 | outputPath = resolve(process.cwd(), outputPath);
16 | }
17 | argv.outputFilename = basename(outputPath); // eslint-disable-line no-param-reassign
18 | argv.outputPath = dirname(outputPath); // eslint-disable-line no-param-reassign
19 | }
20 |
21 | for (const key of keys) {
22 | const arg = camelcase(key);
23 | let value = argv[arg];
24 |
25 | if (value) {
26 | if (arg === 'outputPath') {
27 | value = resolve(value);
28 | }
29 |
30 | if (typeof value !== 'undefined') {
31 | output[camelcase(key.replace('output-', ''))] = value;
32 | }
33 | }
34 | }
35 |
36 | return merge(options, { output });
37 | },
38 |
39 | flags: {
40 | output: {
41 | alias: 'o',
42 | desc: 'The output path and file for compilation assets',
43 | type: 'string',
44 | },
45 | 'output-chunk-filename': {
46 | desc: 'The output filename for additional chunks',
47 | type: 'string',
48 | },
49 | 'output-filename': {
50 | desc: 'The output filename of the bundle',
51 | type: 'string',
52 | },
53 | 'output-jsonp-function': {
54 | desc: 'The name of the JSONP function used for chunk loading',
55 | type: 'string',
56 | },
57 | 'output-library': {
58 | desc: 'Expose the exports of the entry point as library',
59 | type: 'string',
60 | },
61 | 'output-library-target': {
62 | desc: 'The type for exposing the exports of the entry point as library',
63 | type: 'string',
64 | },
65 | 'output-path': {
66 | desc: 'The output path for compilation assets',
67 | type: 'string',
68 | },
69 | 'output-pathinfo': {
70 | desc:
71 | 'Include a comment with the request for every dependency (require, import, etc.)',
72 | type: 'boolean',
73 | },
74 | 'output-public-path': {
75 | desc: 'The public path for the assets',
76 | type: 'string',
77 | },
78 | 'output-source-map-filename': {
79 | desc: 'The output filename for the SourceMap',
80 | type: 'string',
81 | },
82 | },
83 |
84 | name: 'Output',
85 | };
86 |
--------------------------------------------------------------------------------
/test/util.js:
--------------------------------------------------------------------------------
1 | const { readFileSync: read } = require('fs');
2 | const { join } = require('path');
3 |
4 | const camelcaseKeys = require('camelcase-keys');
5 | const { crc32 } = require('crc');
6 | const decamel = require('decamelize');
7 | const buildMinimistOptions = require('minimist-options');
8 | const minimist = require('minimist');
9 |
10 | const compiler = require('../lib/compiler');
11 | const { validate } = require('../lib/flags/util');
12 |
13 | function prep(options) {
14 | const fixtureType = options.fixtureType || 'flags';
15 | /* eslint-disable global-require, import/no-dynamic-require */
16 | const fixture = require(`./fixtures/${fixtureType}/${options.fixture}`);
17 | const group = require(`../lib/flags/${fixture.group}`);
18 | const args = fixture.arguments;
19 | const minimistOpts = buildMinimistOptions(
20 | Object.assign({ arguments: 'string' }, fixture.flags)
21 | );
22 |
23 | let argv = minimist(args, minimistOpts);
24 | argv = camelcaseKeys(argv, { exclude: ['--', /^\w$/] });
25 |
26 | delete argv._;
27 |
28 | return { argv, fixture, group };
29 | /* eslint-enable global-require, import/no-dynamic-require */
30 | }
31 |
32 | module.exports = {
33 | apply(options) {
34 | const { argv, fixture, group } = prep(options);
35 | const { config } = fixture;
36 |
37 | const result = [].concat(config).map((conf) => group.apply(argv, conf));
38 |
39 | return result.length > 1 ? result : result[0];
40 | },
41 |
42 | build(config) {
43 | return compiler(config).run();
44 | },
45 |
46 | crcDist(filePath) {
47 | const readPath = filePath || join(__dirname, '../dist/main.js');
48 | const content = read(readPath, 'utf-8');
49 |
50 | return crc32(content).toString(16);
51 | },
52 |
53 | distContains(what) {
54 | const content = read(join(__dirname, '../dist/main.js'), 'utf-8');
55 |
56 | if (what instanceof RegExp) {
57 | return what.test(content);
58 | }
59 |
60 | return content.indexOf(what) >= 0;
61 | },
62 |
63 | prep,
64 |
65 | test(title, module, fn) {
66 | describe(title, function desc() {
67 | this.beforeEach(function be() {
68 | this.currentTest.file = module.filename;
69 | });
70 | fn();
71 | });
72 | },
73 |
74 | validate(options) {
75 | const { argv, group } = prep(options);
76 |
77 | for (const key of Object.keys(argv)) {
78 | const arg = decamel(key, '-');
79 | const flag = group.flags[arg];
80 |
81 | if (flag) {
82 | const value = argv[key];
83 |
84 | if (!validate(flag, value)) {
85 | throw new Error(
86 | `\`--${key}\` does not match type(s) \`${flag.type}\``
87 | );
88 | }
89 | }
90 | }
91 |
92 | return true;
93 | },
94 | };
95 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/entry.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --entry > multi should apply #0 1`] = `
4 | Object {
5 | "entry": Object {
6 | "main": Array [
7 | "./test/fixtures/common/entry-a.js",
8 | "./test/fixtures/common/entry-b.js",
9 | ],
10 | },
11 | "mode": "development",
12 | "plugins": Array [
13 | NamedModulesPlugin {
14 | "options": Object {},
15 | },
16 | ],
17 | "reporter": "/test/fixtures/common/test-reporter.js",
18 | }
19 | `;
20 |
21 | exports[`Flags > --entry > multi should build #0 1`] = `
22 | "Version: webpack 4.14.0
23 | Asset Size Chunks Chunk Names
24 | main.js 4.95 KiB main [emitted] main
25 | Entrypoint main = main.js
26 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]
27 | [./test/fixtures/common/entry-b.js] 41 bytes {main} [built]
28 | [0] multi ./test/fixtures/common/entry-a.js ./test/fixtures/common/entry-b.js 40 bytes {main} [built]"
29 | `;
30 |
31 | exports[`Flags > --entry > multi should build #1 1`] = `"f217c90d"`;
32 |
33 | exports[`Flags > --entry > should parse flag array #0 1`] = `
34 | Object {
35 | "main": Array [
36 | "/test/fixtures/common/entry-a.js",
37 | "/test/fixtures/common/entry-b.js",
38 | ],
39 | }
40 | `;
41 |
42 | exports[`Flags > --entry > should parse flag object #0 1`] = `
43 | Object {
44 | "a": "/test/fixtures/common/entry-a.js",
45 | "b": "/test/fixtures/common/entry-b.js",
46 | }
47 | `;
48 |
49 | exports[`Flags > --entry > should parse input #0 1`] = `
50 | Object {
51 | "main": Array [
52 | "/test/fixtures/common/entry-a.js",
53 | "/test/fixtures/common/entry-c.js",
54 | ],
55 | }
56 | `;
57 |
58 | exports[`Flags > --entry > should parse input + flag array #0 1`] = `
59 | Object {
60 | "main": Array [
61 | "/test/fixtures/common/entry-a.js",
62 | "/test/fixtures/common/entry-b.js",
63 | "/test/fixtures/common/entry-c.js",
64 | ],
65 | }
66 | `;
67 |
68 | exports[`Flags > --entry > should parse input + flag object #0 1`] = `
69 | Object {
70 | "a": "/test/fixtures/common/entry-a.js",
71 | "b": "/test/fixtures/common/entry-b.js",
72 | "main": "/test/fixtures/common/entry-a.js",
73 | }
74 | `;
75 |
76 | exports[`Flags > --entry > should parse input + single flag #0 1`] = `
77 | Object {
78 | "main": Array [
79 | "/test/fixtures/common/entry-a.js",
80 | "/test/fixtures/common/entry-b.js",
81 | ],
82 | }
83 | `;
84 |
85 | exports[`Flags > --entry > should parse single flag #0 1`] = `
86 | Object {
87 | "main": "/test/fixtures/common/entry-a.js",
88 | }
89 | `;
90 |
--------------------------------------------------------------------------------
/test/tests/__snapshots__/config.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`lib/config > distill() #0 1`] = `
4 | Array [
5 | Object {
6 | "context": "",
7 | "entry": "/common/entry-a.js",
8 | "mode": "development",
9 | },
10 | Object {
11 | "context": "",
12 | "entry": "/common/entry-b.js",
13 | "mode": "development",
14 | },
15 | ]
16 | `;
17 |
18 | exports[`lib/config > distill() --config-name #0 1`] = `
19 | Object {
20 | "entry": "/common/entry-b.js",
21 | "mode": "development",
22 | "name": "test",
23 | "plugins": Array [
24 | 1,
25 | ],
26 | }
27 | `;
28 |
29 | exports[`lib/config > distill() plugins #0 1`] = `
30 | Object {
31 | "context": "",
32 | "plugins": Array [
33 | 1,
34 | ],
35 | }
36 | `;
37 |
38 | exports[`lib/config > distill() plugins #1 1`] = `
39 | Object {
40 | "context": "",
41 | "plugins": Array [
42 | 1,
43 | ],
44 | }
45 | `;
46 |
47 | exports[`lib/config > distill() plugins #2 1`] = `
48 | Object {
49 | "context": "",
50 | "plugins": Array [
51 | 1,
52 | 1,
53 | ],
54 | }
55 | `;
56 |
57 | exports[`lib/config > distill() plugins from config array #0 1`] = `
58 | Array [
59 | Object {
60 | "context": "",
61 | "entry": "/common/entry-a.js",
62 | "mode": "development",
63 | "plugins": Array [
64 | 1,
65 | ],
66 | },
67 | Object {
68 | "context": "",
69 | "entry": "/common/entry-b.js",
70 | "mode": "development",
71 | "plugins": Array [
72 | 1,
73 | ],
74 | },
75 | ]
76 | `;
77 |
78 | exports[`lib/config > distill() plugins from config array #1 1`] = `
79 | Array [
80 | Object {
81 | "context": "",
82 | "entry": "/common/entry-a.js",
83 | "mode": "development",
84 | "plugins": Array [
85 | 1,
86 | ],
87 | },
88 | Object {
89 | "context": "",
90 | "entry": "/common/entry-b.js",
91 | "mode": "development",
92 | "plugins": Array [
93 | 1,
94 | ],
95 | },
96 | ]
97 | `;
98 |
99 | exports[`lib/config > distill() plugins from config array #2 1`] = `
100 | Array [
101 | Object {
102 | "context": "",
103 | "entry": "/common/entry-a.js",
104 | "mode": "development",
105 | "plugins": Array [
106 | 1,
107 | ],
108 | },
109 | Object {
110 | "context": "",
111 | "entry": "/common/entry-b.js",
112 | "mode": "development",
113 | "plugins": Array [
114 | 1,
115 | 1,
116 | ],
117 | },
118 | ]
119 | `;
120 |
--------------------------------------------------------------------------------
/lib/commands/TeachCommand.js:
--------------------------------------------------------------------------------
1 | const { readFileSync: read, writeFileSync: write } = require('fs');
2 | const { join } = require('path');
3 |
4 | const chalk = require('chalk');
5 |
6 | const pkg = require('../../package.json');
7 |
8 | const Command = require('./Command');
9 |
10 | class TeachCommandError extends Command.CommandError {
11 | constructor(...args) {
12 | super(...args);
13 | this.name = 'TeachCommandError';
14 | }
15 | }
16 |
17 | module.exports = class TeachCommand extends Command {
18 | help() {
19 | return chalk`
20 | {blue teach} v${pkg.version}
21 |
22 | Teaches webpack-command that a command has been installed and is available.
23 |
24 | {underline Usage}
25 | $ webpack teach --command --module
26 |
27 | {underline Options}
28 | --command The name of a command that users will type
29 | --forget Instructs the tool to forget a previously added command
30 | --module The npm module name of a command
31 |
32 | {underline Examples}
33 | $ webpack teach --command init --module webpack-command-init
34 | $ webpack teach --command init --forget
35 | `;
36 | }
37 |
38 | run(cli) {
39 | const { flags } = cli;
40 | const { command, forget, module: commandModule } = flags;
41 | const dataPath = join(__dirname, '../../data/commands.json');
42 | const dataFile = read(dataPath, 'utf-8');
43 | const commands = JSON.parse(dataFile);
44 | const format = () =>
45 | JSON.stringify(commands, Object.keys(commands).sort(), 2);
46 |
47 | if (!command) {
48 | throw new TeachCommandError('The --command flag is required.');
49 | }
50 |
51 | if (typeof command !== 'string') {
52 | throw new TeachCommandError('The value of --command must be a String.');
53 | }
54 |
55 | if (forget) {
56 | delete commands[command];
57 | write(dataPath, format(), 'utf-8');
58 | return;
59 | }
60 |
61 | if (!commandModule) {
62 | throw new TeachCommandError('The --module flag is required.');
63 | }
64 |
65 | if (typeof commandModule !== 'string') {
66 | throw new TeachCommandError('The value of --module must be a String.');
67 | }
68 |
69 | if (commands[command]) {
70 | throw new TeachCommandError(
71 | `The '${command}' command was already added via ${
72 | commands[command]
73 | }. Use \`webpack teach --command ${command} --forget\` and try again.`
74 | );
75 | }
76 |
77 | try {
78 | // eslint-disable-next-line global-require, import/no-dynamic-require
79 | require(commandModule);
80 | } catch (e) {
81 | throw new TeachCommandError(
82 | `The command module '${commandModule}' was not found.`
83 | );
84 | }
85 |
86 | commands[command] = commandModule;
87 |
88 | write(dataPath, format(), 'utf-8');
89 | }
90 | };
91 |
--------------------------------------------------------------------------------
/test/tests/flags/module-bind.js:
--------------------------------------------------------------------------------
1 | const {
2 | apply,
3 | build,
4 | crcDist,
5 | distContains,
6 | test,
7 | validate,
8 | } = require('../../util');
9 |
10 | test('--module-bind', module, () => {
11 | const fixture = `module-bind/bind`;
12 | const opts = { fixture };
13 |
14 | let config;
15 |
16 | it(`should validate`, () => {
17 | expect(validate(opts)).toEqual(true);
18 | });
19 |
20 | it(`should apply`, () => {
21 | config = apply(opts);
22 |
23 | expect(config).toMatchSnapshot();
24 | });
25 |
26 | it(`should bind and build`, () =>
27 | build(config).then((result) => {
28 | expect(distContains('loader: module.exports')).toBe(true);
29 | expect(result).toMatchSnapshot();
30 | expect(crcDist()).toMatchSnapshot();
31 | }));
32 | });
33 |
34 | test('--module-bind-pre', module, () => {
35 | const fixture = `module-bind/bind-pre`;
36 | const opts = { fixture };
37 |
38 | let config;
39 |
40 | it(`should validate`, () => {
41 | expect(validate(opts)).toEqual(true);
42 | });
43 |
44 | it(`should apply`, () => {
45 | config = apply(opts);
46 |
47 | expect(config).toMatchSnapshot();
48 | });
49 |
50 | it(`should bind and build`, () =>
51 | build(config).then((result) => {
52 | expect(distContains(`pre = true`)).toBe(true);
53 | expect(result).toMatchSnapshot();
54 | expect(crcDist()).toMatchSnapshot();
55 | }));
56 | });
57 |
58 | test('--module-bind-post', module, () => {
59 | const fixture = `module-bind/bind-post`;
60 | const opts = { fixture };
61 |
62 | let config;
63 |
64 | it(`should validate`, () => {
65 | expect(validate(opts)).toEqual(true);
66 | });
67 |
68 | it(`should apply`, () => {
69 | config = apply(opts);
70 |
71 | expect(config).toMatchSnapshot();
72 | });
73 |
74 | it(`should bind and build`, () =>
75 | build(config).then((result) => {
76 | expect(distContains(`post = true`)).toBe(true);
77 | expect(result).toMatchSnapshot();
78 | expect(crcDist()).toMatchSnapshot();
79 | }));
80 | });
81 |
82 | test('--module-bind-all', module, () => {
83 | const fixture = `module-bind/bind-all`;
84 | const opts = { fixture };
85 |
86 | let config;
87 |
88 | it(`should validate`, () => {
89 | expect(validate(opts)).toEqual(true);
90 | });
91 |
92 | it(`should apply`, () => {
93 | config = apply(opts);
94 |
95 | expect(config).toMatchSnapshot();
96 | });
97 |
98 | it(`should bind and build`, () =>
99 | build(config).then((result) => {
100 | expect(distContains(`pre = true`)).toBe(true);
101 | expect(distContains(`post = true`)).toBe(true);
102 | expect(result).toMatchSnapshot();
103 | expect(crcDist()).toMatchSnapshot();
104 | }));
105 | });
106 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/optimize.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --optimize-* > max-chunks should apply #0 1`] = `
4 | Object {
5 | "entry": Array [
6 | "/test/fixtures/common/entry-a.js",
7 | "/test/fixtures/common/entry-b.js",
8 | "/test/fixtures/common/entry-c.js",
9 | ],
10 | "mode": "development",
11 | "plugins": Array [
12 | LimitChunkCountPlugin {
13 | "options": Object {
14 | "maxChunks": 1000,
15 | },
16 | },
17 | NamedModulesPlugin {
18 | "options": Object {},
19 | },
20 | ],
21 | "reporter": "/test/fixtures/common/test-reporter.js",
22 | }
23 | `;
24 |
25 | exports[`Flags > --optimize-* > max-chunks should build #0 1`] = `
26 | "Version: webpack 4.14.0
27 | Asset Size Chunks Chunk Names
28 | main.js main [emitted] main
29 | Entrypoint main = main.js
30 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]
31 | [./test/fixtures/common/entry-b.js] 41 bytes {main} [built]
32 | [./test/fixtures/common/entry-c.js] 41 bytes {main} [built]
33 | [0] multi ./test/fixtures/common/entry-a.js ./test/fixtures/common/entry-b.js ./test/fixtures/common/entry-c.js 52 bytes {main} [built]"
34 | `;
35 |
36 | exports[`Flags > --optimize-* > min-chunk-size should apply #0 1`] = `
37 | Object {
38 | "entry": "/test/fixtures/common/entry-a.js",
39 | "mode": "development",
40 | "plugins": Array [
41 | MinChunkSizePlugin {
42 | "options": Object {
43 | "minChunkSize": 10,
44 | },
45 | },
46 | NamedModulesPlugin {
47 | "options": Object {},
48 | },
49 | ],
50 | "reporter": "/test/fixtures/common/test-reporter.js",
51 | }
52 | `;
53 |
54 | exports[`Flags > --optimize-* > min-chunk-size should build #0 1`] = `
55 | "Version: webpack 4.14.0
56 | Asset Size Chunks Chunk Names
57 | main.js main [emitted] main
58 | Entrypoint main = main.js
59 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
60 | `;
61 |
62 | exports[`Flags > --optimize-* > minimize should apply #0 1`] = `
63 | Object {
64 | "entry": "/test/fixtures/common/entry-a.js",
65 | "mode": "development",
66 | "plugins": Array [
67 | LoaderOptionsPlugin {
68 | "options": Object {
69 | "minimize": true,
70 | "test": Object {
71 | "test": [Function],
72 | },
73 | },
74 | },
75 | NamedModulesPlugin {
76 | "options": Object {},
77 | },
78 | ],
79 | "reporter": "/test/fixtures/common/test-reporter.js",
80 | }
81 | `;
82 |
83 | exports[`Flags > --optimize-* > minimize should build #0 1`] = `
84 | "Version: webpack 4.14.0
85 | Asset Size Chunks Chunk Names
86 | main.js main [emitted] main
87 | Entrypoint main = main.js
88 | [./test/fixtures/common/entry-a.js] 41 bytes {main} [built]"
89 | `;
90 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/resolve.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --resolve-* > resolve-alias reporter should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/flags/resolve/entry.js",
6 | "mode": "development",
7 | "plugins": Array [
8 | NamedModulesPlugin {
9 | "options": Object {},
10 | },
11 | ],
12 | "reporter": "/test/fixtures/common/test-reporter.js",
13 | "resolve": Object {
14 | "alias": Object {
15 | "aliased": "/test/fixtures/flags/resolve/aliased",
16 | },
17 | },
18 | }
19 | `;
20 |
21 | exports[`Flags > --resolve-* > resolve-alias reporter should build #0 1`] = `
22 | "Version: webpack 4.14.0
23 | Asset Size Chunks Chunk Names
24 | main.js 4.61 KiB main [emitted] main
25 | Entrypoint main = main.js
26 | [./test/fixtures/flags/resolve/aliased/dependency.js] 39 bytes {main} [built]
27 | [./test/fixtures/flags/resolve/entry.js] 150 bytes {main} [built]"
28 | `;
29 |
30 | exports[`Flags > --resolve-* > resolve-alias reporter should build #1 1`] = `"23f35c9e"`;
31 |
32 | exports[`Flags > --resolve-* > resolve-extensions reporter should apply #0 1`] = `
33 | Object {
34 | "entry": "/test/fixtures/flags/resolve/entry-extensions.js",
35 | "mode": "development",
36 | "plugins": Array [
37 | NamedModulesPlugin {
38 | "options": Object {},
39 | },
40 | ],
41 | "reporter": "/test/fixtures/common/test-reporter.js",
42 | "resolve": Object {
43 | "extensions": Array [
44 | ".custom",
45 | ],
46 | },
47 | }
48 | `;
49 |
50 | exports[`Flags > --resolve-* > resolve-extensions reporter should build #0 1`] = `
51 | "Version: webpack 4.14.0
52 | Asset Size Chunks Chunk Names
53 | main.js 4.64 KiB main [emitted] main
54 | Entrypoint main = main.js
55 | [./test/fixtures/flags/resolve/dependency.custom] 38 bytes {main} [built]
56 | [./test/fixtures/flags/resolve/entry-extensions.js] 144 bytes {main} [built]"
57 | `;
58 |
59 | exports[`Flags > --resolve-* > resolve-extensions reporter should build #1 1`] = `"4ae3815"`;
60 |
61 | exports[`Flags > --resolve-* > resolve-loader-alias reporter should apply #0 1`] = `
62 | Object {
63 | "entry": "/test/fixtures/flags/resolve/entry-loader-alias.js",
64 | "mode": "development",
65 | "plugins": Array [
66 | NamedModulesPlugin {
67 | "options": Object {},
68 | },
69 | ],
70 | "reporter": "/test/fixtures/common/test-reporter.js",
71 | "resolveLoader": undefined,
72 | }
73 | `;
74 |
75 | exports[`Flags > --resolve-* > resolve-loader-alias reporter should build #0 1`] = `
76 | "Version: webpack 4.14.0
77 | Asset Size Chunks Chunk Names
78 | main.js 17.9 KiB main [emitted] main
79 | Entrypoint main = main.js
80 | [./node_modules/path-browserify/index.js] 6.04 KiB {main} [built]
81 | [./node_modules/process/browser.js] 5.29 KiB {main} [built]
82 | [./test/fixtures/flags/resolve sync recursive ^aliased!.*$] ./test/fixtures/flags/resolve sync ^aliased!.*$ 160 bytes {main} [built]
83 | [./test/fixtures/flags/resolve/entry-loader-alias.js] 283 bytes {main} [built]"
84 | `;
85 |
86 | exports[`Flags > --resolve-* > resolve-loader-alias reporter should build #1 1`] = `"9a21ea9e"`;
87 |
--------------------------------------------------------------------------------
/test/tests/commands/__snapshots__/help.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`help command > should display all commands #0 1`] = `
4 | " help
5 | teach"
6 | `;
7 |
8 | exports[`help command > should display help #0 1`] = `
9 | "
10 | [34mhelp[39m v
11 |
12 | Displays help for a given installed webpack command.
13 |
14 | [4mUsage[24m
15 | $ webpack help
16 |
17 | [4mExamples[24m
18 | $ webpack help
19 | $ webpack help init
20 | $ webpack help serve
21 | "
22 | `;
23 |
24 | exports[`help command > should display help #1 1`] = `
25 | "
26 | [34mhelp[39m v
27 |
28 | Displays help for a given installed webpack command.
29 |
30 | [4mUsage[24m
31 | $ webpack help
32 |
33 | [4mExamples[24m
34 | $ webpack help
35 | $ webpack help init
36 | $ webpack help serve
37 | "
38 | `;
39 |
40 | exports[`help command > should display help for the help command #0 1`] = `
41 | "
42 | [34mhelp[39m v
43 |
44 | Displays help for a given installed webpack command.
45 |
46 | [4mUsage[24m
47 | $ webpack help
48 |
49 | [4mExamples[24m
50 | $ webpack help
51 | $ webpack help init
52 | $ webpack help serve
53 | "
54 | `;
55 |
56 | exports[`help command > should display help for the teach command #0 1`] = `
57 | "
58 | [34mteach[39m v
59 |
60 | Teaches webpack-command that a command has been installed and is available.
61 |
62 | [4mUsage[24m
63 | $ webpack teach --command --module
64 |
65 | [4mOptions[24m
66 | --command The name of a command that users will type
67 | --forget Instructs the tool to forget a previously added command
68 | --module The npm module name of a command
69 |
70 | [4mExamples[24m
71 | $ webpack teach --command init --module webpack-command-init
72 | $ webpack teach --command init --forget
73 | "
74 | `;
75 |
76 | exports[`lib/flags > should display all commands #0 1`] = `
77 | " help
78 | teach"
79 | `;
80 |
81 | exports[`lib/flags > should display help #0 1`] = `
82 | "
83 | [34mhelp[39m v0.0.0
84 |
85 | Displays help for a given installed webpack command.
86 |
87 | [4mUsage[24m
88 | $ webpack help
89 |
90 | [4mExamples[24m
91 | $ webpack help init
92 | $ webpack help serve
93 | "
94 | `;
95 |
96 | exports[`lib/flags > should display help for the help command #0 1`] = `
97 | "
98 | [34mhelp[39m v0.0.0
99 |
100 | Displays help for a given installed webpack command.
101 |
102 | [4mUsage[24m
103 | $ webpack help
104 |
105 | [4mExamples[24m
106 | $ webpack help init
107 | $ webpack help serve
108 | "
109 | `;
110 |
111 | exports[`lib/flags > should display help for the teach command #0 1`] = `
112 | "
113 | [34mteach[39m v0.0.0
114 |
115 | Teaches webpack-command that a command has been installed and is available.
116 |
117 | [4mUsage[24m
118 | $ webpack teach --command --module
119 |
120 | [4mOptions[24m
121 | --command The name of a command that users will type
122 | --forget Instructs the tool to forget a previously added command
123 | --module The npm module name of a command
124 |
125 | [4mExamples[24m
126 | $ webpack teach --command init --module webpack-command-init
127 | "
128 | `;
129 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/nonstandard/.stylelintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "at-rule-empty-line-before": [ "always", {
4 | "except": [ "blockless-after-blockless", "first-nested" ],
5 | "ignore": ["after-comment"],
6 | } ],
7 | "block-closing-brace-newline-after": "always",
8 | "block-closing-brace-newline-before": "always-multi-line",
9 | "block-closing-brace-space-before": "always-single-line",
10 | "block-no-empty": true,
11 | "block-opening-brace-newline-after": "always-multi-line",
12 | "block-opening-brace-space-after": "always-single-line",
13 | "block-opening-brace-space-before": "always",
14 | "color-hex-case": [ "lower", { "severity": "warning" }
15 | ],
16 | "color-hex-length": "short",
17 | "color-no-invalid-hex": true,
18 | "comment-empty-line-before": [ "always", {
19 | "except": ["first-nested"],
20 | "ignore": ["stylelint-commands"],
21 | } ],
22 | "comment-whitespace-inside": "always",
23 | "declaration-bang-space-after": "never",
24 | "declaration-bang-space-before": "always",
25 | "declaration-block-no-shorthand-property-overrides": true,
26 | "declaration-block-semicolon-newline-after": "always-multi-line",
27 | "declaration-block-semicolon-space-after": "always-single-line",
28 | "declaration-block-semicolon-space-before": "never",
29 | "declaration-block-single-line-max-declarations": 1,
30 | "declaration-block-trailing-semicolon": "always",
31 | "declaration-colon-newline-after": "always-multi-line",
32 | "declaration-colon-space-after": "always-single-line",
33 | "declaration-colon-space-before": "never",
34 | "font-family-name-quotes": "always-unless-keyword",
35 | "function-calc-no-unspaced-operator": true,
36 | "function-comma-newline-after": "always-multi-line",
37 | "function-comma-space-after": "always-single-line",
38 | "function-comma-space-before": "never",
39 | "function-linear-gradient-no-nonstandard-direction": true,
40 | "function-parentheses-newline-inside": "always-multi-line",
41 | "function-parentheses-space-inside": "never-single-line",
42 | "function-whitespace-after": "always",
43 | "indentation": 2,
44 | "length-zero-no-unit": true,
45 | "max-empty-lines": 1,
46 | "media-feature-colon-space-after": "always",
47 | "media-feature-colon-space-before": "never",
48 | "media-feature-parentheses-space-inside": "never",
49 | "media-feature-range-operator-space-after": "always",
50 | "media-feature-range-operator-space-before": "always",
51 | "media-query-list-comma-newline-after": "always-multi-line",
52 | "media-query-list-comma-space-after": "always-single-line",
53 | "media-query-list-comma-space-before": "never",
54 | "no-eol-whitespace": true,
55 | "no-invalid-double-slash-comments": true,
56 | "no-missing-end-of-source-newline": true,
57 | "number-leading-zero": "always",
58 | "number-no-trailing-zeros": true,
59 | "selector-combinator-space-after": "always",
60 | "selector-combinator-space-before": "always",
61 | "selector-list-comma-newline-after": "always",
62 | "selector-list-comma-space-before": "never",
63 | "selector-pseudo-element-colon-notation": "double",
64 | "string-no-newline": true,
65 | "string-quotes": "double",
66 | "value-list-comma-newline-after": "always-multi-line",
67 | "value-list-comma-space-after": "always-single-line",
68 | "value-list-comma-space-before": "never",
69 | },
70 | }
71 |
--------------------------------------------------------------------------------
/test/fixtures/reporters/stylish/nonstandard/bad-rule.stylelintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "at-rule-empty-line-before": [ "always", {
4 | "except": [ "blockless-after-blockless", "first-nested" ],
5 | "ignore": ["after-comment"],
6 | } ],
7 | "block-closing-brace-newline-after": "always",
8 | "block-closing-brace-newline-before": "always-multi-line",
9 | "block-closing-brace-space-before": "always-single-line",
10 | "block-no-empty": "ZOMG",
11 | "block-opening-brace-newline-after": "always-multi-line",
12 | "block-opening-brace-space-after": "always-single-line",
13 | "block-opening-brace-space-before": "always",
14 | "color-hex-case": [ "lower", { "severity": "warning" }
15 | ],
16 | "color-hex-length": "short",
17 | "color-no-invalid-hex": true,
18 | "comment-empty-line-before": [ "always", {
19 | "except": ["first-nested"],
20 | "ignore": ["stylelint-commands"],
21 | } ],
22 | "comment-whitespace-inside": "always",
23 | "declaration-bang-space-after": "never",
24 | "declaration-bang-space-before": "always",
25 | "declaration-block-no-shorthand-property-overrides": true,
26 | "declaration-block-semicolon-newline-after": "always-multi-line",
27 | "declaration-block-semicolon-space-after": "always-single-line",
28 | "declaration-block-semicolon-space-before": "never",
29 | "declaration-block-single-line-max-declarations": 1,
30 | "declaration-block-trailing-semicolon": "always",
31 | "declaration-colon-newline-after": "always-multi-line",
32 | "declaration-colon-space-after": "always-single-line",
33 | "declaration-colon-space-before": "never",
34 | "font-family-name-quotes": "always-unless-keyword",
35 | "function-calc-no-unspaced-operator": true,
36 | "function-comma-newline-after": "always-multi-line",
37 | "function-comma-space-after": "always-single-line",
38 | "function-comma-space-before": "never",
39 | "function-linear-gradient-no-nonstandard-direction": true,
40 | "function-parentheses-newline-inside": "always-multi-line",
41 | "function-parentheses-space-inside": "never-single-line",
42 | "function-whitespace-after": "always",
43 | "indentation": 2,
44 | "length-zero-no-unit": true,
45 | "max-empty-lines": 1,
46 | "media-feature-colon-space-after": "always",
47 | "media-feature-colon-space-before": "never",
48 | "media-feature-parentheses-space-inside": "never",
49 | "media-feature-range-operator-space-after": "always",
50 | "media-feature-range-operator-space-before": "always",
51 | "media-query-list-comma-newline-after": "always-multi-line",
52 | "media-query-list-comma-space-after": "always-single-line",
53 | "media-query-list-comma-space-before": "never",
54 | "no-eol-whitespace": true,
55 | "no-invalid-double-slash-comments": true,
56 | "no-missing-end-of-source-newline": true,
57 | "number-leading-zero": "always",
58 | "number-no-trailing-zeros": true,
59 | "selector-combinator-space-after": "always",
60 | "selector-combinator-space-before": "always",
61 | "selector-list-comma-newline-after": "always",
62 | "selector-list-comma-space-before": "never",
63 | "selector-pseudo-element-colon-notation": "double",
64 | "string-no-newline": true,
65 | "string-quotes": "double",
66 | "value-list-comma-newline-after": "always-multi-line",
67 | "value-list-comma-space-after": "always-single-line",
68 | "value-list-comma-space-before": "never",
69 | },
70 | }
71 |
--------------------------------------------------------------------------------
/test/tests/cli.js:
--------------------------------------------------------------------------------
1 | const execa = require('execa');
2 | const strip = require('strip-ansi');
3 |
4 | const { test } = require('../util');
5 |
6 | test('Bad Config', module, () => {
7 | it('should run', () => {
8 | const cliPath = resolve(__dirname, '../../lib/cli');
9 | const cwd = resolve(__dirname, '../fixtures/bad-config');
10 |
11 | try {
12 | execa.sync('node', [cliPath], { cwd });
13 | } catch (e) {
14 | expect(e.message).toMatch(
15 | `options['batman'] is an invalid additional property`
16 | );
17 | }
18 | });
19 | });
20 |
21 | test('Zero Config', module, () => {
22 | it('should run', () => {
23 | const cliPath = resolve(__dirname, '../../lib/cli');
24 | const cwd = resolve(__dirname, '../fixtures/zero-config');
25 | const result = execa.sync('node', [cliPath], { cwd });
26 |
27 | expect(
28 | strip(result.stdout)
29 | .replace(/Δt \d+ms/g, '')
30 | .replace(/v\d\.\d\.\d/, '')
31 | ).toMatchSnapshot();
32 | }).timeout(4000);
33 | });
34 |
35 | test('Commands', module, () => {
36 | it('should show cli help', () => {
37 | const cliPath = resolve(__dirname, '../../lib/cli.js');
38 | const result = execa.sync('node', [cliPath, '--help']);
39 |
40 | expect(
41 | strip(result.stdout).replace(/Δt \d+ms/g, '')
42 | ).toMatchSnapshot();
43 | });
44 |
45 | it('should show teach command help', () => {
46 | const cliPath = resolve(__dirname, '../../lib/cli.js');
47 | const result = execa.sync(cliPath, ['help', 'teach']);
48 |
49 | expect(result.stdout.replace(/v\d\.\d\.\d/, '')).toMatchSnapshot();
50 | }).timeout(4000);
51 |
52 | it('should throw on command error', () => {
53 | const cliPath = resolve(__dirname, '../../lib/cli.js');
54 | const stub = () => execa.sync(cliPath, ['help', 'bad-command']);
55 |
56 | // TODO: move to error codes
57 | expect(stub).toThrow(/'bad-command' has not been installed/);
58 | }).timeout(4000);
59 |
60 | it('should throw on missing command', () => {
61 | const cliPath = resolve(__dirname, '../../lib/cli.js');
62 | const stub = () =>
63 | execa.sync(cliPath, ['bad-command'], {
64 | env: {
65 | CLI_TEST: 'true',
66 | },
67 | });
68 |
69 | // TODO: move to error codes
70 | expect(stub).toThrow(/bad-command/);
71 | }).timeout(4000);
72 |
73 | it('should add directories to entries', () => {
74 | const cliPath = resolve(__dirname, '../../lib/cli.js');
75 | const srcPath = resolve(__dirname, '../../test/fixtures/flags/config/src');
76 | const result = execa.sync(cliPath, [srcPath]);
77 |
78 | expect(
79 | strip(result.stdout).replace(/Δt \d+ms/g, '')
80 | ).toMatchSnapshot();
81 | }).timeout(4000);
82 |
83 | it('should accept custom reporters relative to the current working directory', () => {
84 | const cliPath = resolve(__dirname, '../../lib/cli.js');
85 | const srcPath = resolve(__dirname, '../../test/fixtures/flags/config/src');
86 | const result = execa.sync(
87 | cliPath,
88 | ['--reporter', '../../lib/reporters/BasicReporter', srcPath],
89 | {
90 | cwd: __dirname,
91 | }
92 | );
93 |
94 | expect(
95 | strip(result.stdout)
96 | .replace(/Version: webpack \d+\.\d+\.\d+/, '')
97 | .replace(/Time: \d+ms/g, '')
98 | .replace(/Built at: .+(?=\n)/g, '')
99 | .replace(/[a-f0-9]{20}/g, '')
100 | .replace(/\d+ bytes/g, '')
101 | ).toMatchSnapshot();
102 | }).timeout(4000);
103 | });
104 |
--------------------------------------------------------------------------------
/lib/flags/index.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 | const merge = require('merge-options');
3 | const strip = require('strip-ansi');
4 | const table = require('text-table');
5 |
6 | const advanced = require('./advanced.js');
7 | const config = require('./config.js'); // eslint
8 | const general = require('./general.js');
9 | const modul = require('./module.js'); // eslint
10 | const optimization = require('./optimization.js'); // eslint
11 | const output = require('./output.js'); // eslint
12 | const resolver = require('./resolver.js'); // eslint
13 | const { validateFlags } = require('./util');
14 |
15 | const allFlags = [
16 | general,
17 | advanced,
18 | config,
19 | modul,
20 | optimization,
21 | output,
22 | resolver,
23 | ];
24 |
25 | function getGroupHelp(group) {
26 | const rows = [];
27 | const { name } = group;
28 |
29 | if (name !== 'General') {
30 | rows.push([chalk`{underline ${group.name}}`, '']);
31 | }
32 |
33 | for (const flagName of Object.keys(group.flags)) {
34 | const flag = group.flags[flagName];
35 | let { desc } = flag;
36 | const { deprecated } = flag;
37 |
38 | if (deprecated) {
39 | desc = chalk`{bold Deprecated.} Please use ${deprecated}.\n${desc}`;
40 | }
41 |
42 | const lines = desc.split('\n');
43 | const [description] = lines.splice(0, 1);
44 |
45 | rows.push([` --${flagName}`, description]);
46 |
47 | if (lines.length > 0) {
48 | for (const line of lines) {
49 | rows.push(['', line]);
50 | }
51 | }
52 | }
53 |
54 | return rows;
55 | }
56 |
57 | module.exports = {
58 | apply(argv, options) {
59 | const groups = allFlags.slice(0);
60 | const { getFlags } = module.exports;
61 | const flags = getFlags();
62 | let result = merge({}, options);
63 |
64 | // two loops may seem silly, but it's good UX to validate all the flags at
65 | // once. this is also familiar to users of linters.
66 | /* istanbul ignore if */
67 | if (!validateFlags(flags, argv)) {
68 | return null;
69 | }
70 |
71 | for (const group of groups) {
72 | result = group.apply(argv, result);
73 | }
74 |
75 | return result;
76 | },
77 |
78 | help() {
79 | let rows = [];
80 | const groups = allFlags.slice(0);
81 | const options = {
82 | align: ['l', 'l'],
83 | stringLength(str) {
84 | return strip(str).length;
85 | },
86 | };
87 |
88 | for (const group of groups) {
89 | rows = rows.concat(getGroupHelp(group));
90 | rows.push(['', '']);
91 | }
92 |
93 | return table(rows, options);
94 | },
95 |
96 | getFlags(includeAlias = true) {
97 | const groups = allFlags.slice(0);
98 | let result = {};
99 |
100 | for (const group of groups) {
101 | const { flags } = group;
102 | result = Object.assign(result, flags);
103 |
104 | if (includeAlias) {
105 | const aliases = {};
106 | for (const flag of Object.values(flags).filter((f) => !!f.alias)) {
107 | aliases[flag.alias] = flag;
108 | }
109 |
110 | result = Object.assign(result, aliases);
111 | }
112 | }
113 |
114 | return result;
115 | },
116 |
117 | opts() {
118 | const result = {};
119 | const groups = allFlags.slice(0);
120 |
121 | for (const group of groups) {
122 | for (const key of Object.keys(group.flags)) {
123 | const flag = Object.assign({}, group.flags[key]);
124 |
125 | delete flag.desc;
126 | delete flag.deprecated;
127 |
128 | result[key] = flag;
129 | }
130 | }
131 |
132 | return result;
133 | },
134 | };
135 |
--------------------------------------------------------------------------------
/lib/reporters/StylishReporter.js:
--------------------------------------------------------------------------------
1 | const capitalize = require('titleize');
2 | const chalk = require('chalk');
3 | const ora = require('ora');
4 |
5 | const parse = require('./parse');
6 | const Reporter = require('./Reporter');
7 |
8 | const style = require('./stylish/style');
9 |
10 | module.exports = class StylishReporter extends Reporter {
11 | constructor(options) {
12 | super(options);
13 |
14 | this.rendered = {
15 | footer: false,
16 | header: false,
17 | };
18 |
19 | this.spinner = ora();
20 |
21 | this.state = {
22 | active: 0,
23 | hashes: [],
24 | instances: 0,
25 | totals: {
26 | errors: 0,
27 | time: 0,
28 | warnings: 0,
29 | },
30 | time: 0,
31 | };
32 | }
33 |
34 | // TODO: create proper testing for this with a large build an stdout hooks.
35 | /* istanbul ignore next */
36 | progress(stage) {
37 | if (!this.spinner.isSpinning && stage.step.percentage < 1) {
38 | this.spinner.start(stage.step.name);
39 | }
40 |
41 | const name = capitalize(stage.step.name);
42 | const percent = Math.floor(stage.step.percentage * 100);
43 |
44 | this.spinner.text = chalk`${name} {dim (${percent}%)}`;
45 |
46 | if (stage.step.percentage >= 1) {
47 | this.spinner.stop();
48 | }
49 | }
50 |
51 | render(error, resultStats) {
52 | if (error) {
53 | return error;
54 | }
55 |
56 | // handles both Stats and MultiStats
57 | const allStats = resultStats.stats || [resultStats];
58 | const compilers = this.compiler.compilers || [this.compiler];
59 | const { compiler, state, rendered } = this;
60 | const { log } = console;
61 | const opts = {
62 | context: compiler.context,
63 | cached: false,
64 | cachedAssets: false,
65 | exclude: ['node_modules', 'bower_components', 'components'],
66 | };
67 | const out = [];
68 | const first = allStats[0].toJson(opts, true);
69 | const { version } = first;
70 |
71 | out.push(chalk.cyan(`\nwebpack v${version}\n`));
72 |
73 | state.instances = allStats.length;
74 |
75 | for (const stats of allStats) {
76 | const json = stats.toJson(opts, true);
77 |
78 | // for --watch more than anything, don't print duplicate output for a hash
79 | // if we've already seen that hash. compensates for a bug in webpack.
80 | if (state.hashes.includes(json.hash)) {
81 | return null;
82 | }
83 |
84 | state.hashes.push(json.hash);
85 | state.time += json.time;
86 |
87 | // errors and warnings go first, to make sure the counts are correct for modules
88 | const compilerIndex = allStats.indexOf(stats);
89 | const compilerOptions = compilers[compilerIndex].options;
90 | const problems = style.problems(parse.problems(json, state));
91 | const files = style.files(parse.files(json), compilerOptions);
92 | const hidden = style.hidden(parse.hidden(json));
93 | const hash = style.hash(json, files, hidden);
94 |
95 | out.push(hash);
96 | out.push(problems);
97 | }
98 |
99 | const footer = style.footer(parse.footer(state));
100 |
101 | if (footer.length) {
102 | rendered.footer = true;
103 | out.push(footer);
104 | }
105 |
106 | state.totals = { errors: 0, time: 0, warnings: 0 };
107 |
108 | const result = out.join('\n');
109 |
110 | log(result);
111 |
112 | if (
113 | rendered.footer &&
114 | compilers.some((comp) => comp.options.watch === true)
115 | ) {
116 | log();
117 | }
118 |
119 | // eslint-disable-next-line consistent-return
120 | return result;
121 | }
122 | };
123 |
--------------------------------------------------------------------------------
/test/tests/flags/entry.js:
--------------------------------------------------------------------------------
1 | const { apply, build, crcDist, prep, test, validate } = require('../../util');
2 | const parseEntries = require('../../../lib/entry');
3 |
4 | test('--entry', module, () => {
5 | it('should parse input', () => {
6 | const entries = [
7 | fixturePath('common/entry-a.js'),
8 | fixturePath('common/entry-c.js'),
9 | ];
10 | const result = parseEntries({ entries, flags: {} });
11 |
12 | expect(result.main).toHaveLength(2);
13 | expect(result).toMatchSnapshot();
14 | });
15 |
16 | it('should parse single flag', () => {
17 | const flags = { entry: fixturePath('common/entry-a.js') };
18 | const result = parseEntries({ entries: [], flags });
19 |
20 | expect(result.main).toEqual(flags.entry);
21 | expect(result).toMatchSnapshot();
22 | });
23 |
24 | it('should parse flag array', () => {
25 | const flags = {
26 | entry: [
27 | fixturePath('common/entry-a.js'),
28 | fixturePath('common/entry-b.js'),
29 | ],
30 | };
31 | const result = parseEntries({ entries: [], flags });
32 |
33 | expect(result.main).toHaveLength(2);
34 | expect(result).toMatchSnapshot();
35 | });
36 |
37 | it('should parse flag object', () => {
38 | const flags = {
39 | entry: {
40 | a: fixturePath('common/entry-a.js'),
41 | b: fixturePath('common/entry-b.js'),
42 | },
43 | };
44 | const result = parseEntries({ entries: [], flags });
45 |
46 | expect(Object.keys(result)).toHaveLength(2);
47 | expect(result).toMatchSnapshot();
48 | });
49 |
50 | it('should parse input + single flag', () => {
51 | const entries = [fixturePath('common/entry-a.js')];
52 | const flags = { entry: fixturePath('common/entry-b.js') };
53 | const result = parseEntries({ entries, flags });
54 |
55 | expect(result.main).toHaveLength(2);
56 | expect(result).toMatchSnapshot();
57 | });
58 |
59 | it('should parse input + flag array', () => {
60 | const entries = [fixturePath('common/entry-a.js')];
61 | const flags = {
62 | entry: [
63 | fixturePath('common/entry-b.js'),
64 | fixturePath('common/entry-c.js'),
65 | ],
66 | };
67 | const result = parseEntries({ entries, flags });
68 |
69 | expect(result.main).toHaveLength(3);
70 | expect(result).toMatchSnapshot();
71 | });
72 |
73 | it('should parse input + flag object', () => {
74 | const entries = [fixturePath('common/entry-a.js')];
75 | const flags = {
76 | entry: {
77 | a: fixturePath('common/entry-a.js'),
78 | b: fixturePath('common/entry-b.js'),
79 | },
80 | };
81 | const result = parseEntries({ entries, flags });
82 |
83 | expect(typeof result.main).toBe('string');
84 | expect(Object.keys(result)).toHaveLength(3);
85 | expect(result).toMatchSnapshot();
86 | });
87 |
88 | for (const name of ['multi' /* , 'single'*/]) {
89 | const fixture = `entry/${name}`;
90 | const opts = { fixture };
91 | let config;
92 |
93 | it(`${name} should validate`, () => {
94 | expect(validate(opts)).toEqual(true);
95 | });
96 |
97 | it(`${name} should apply`, () => {
98 | const { argv } = prep(opts);
99 | const entry = parseEntries({ entries: [], flags: argv });
100 |
101 | config = apply(opts);
102 |
103 | if (entry) {
104 | config.entry = entry;
105 | }
106 |
107 | expect(config).toMatchSnapshot();
108 | });
109 |
110 | it(`${name} should build`, () =>
111 | build(config).then((result) => {
112 | expect(result).toMatchSnapshot();
113 | expect(crcDist()).toMatchSnapshot();
114 | }));
115 | }
116 | });
117 |
--------------------------------------------------------------------------------
/lib/flags/general.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const chalk = require('chalk');
4 | const merge = require('merge-options');
5 | const webpack = require('webpack');
6 |
7 | module.exports = {
8 | apply(argv, options) {
9 | let plugins = [];
10 | const result = {};
11 |
12 | if (options.plugins) {
13 | plugins = plugins.concat(options.plugins);
14 | }
15 |
16 | // NOTE: runDev and runProd should be examined FIRST, as they manipulate
17 | // the argv object. Manipulating argv is bad and should make us feel
18 | // bad.
19 | /* eslint-disable no-param-reassign */
20 | if (argv.runDev) {
21 | argv.debug = true;
22 | argv.outputPathinfo = true;
23 | if (!argv.devtool) {
24 | argv.devtool = 'eval-cheap-module-source-map';
25 | }
26 | if (!argv.mode) {
27 | argv.mode = 'development';
28 | }
29 | }
30 |
31 | if (argv.runProd) {
32 | argv.optimizeMinimize = true;
33 | argv.define = Object.assign({}, argv.define, {
34 | 'process.env.NODE_ENV': '"production"',
35 | });
36 | if (!argv.mode) {
37 | argv.mode = 'production';
38 | }
39 | }
40 |
41 | if (argv.context) {
42 | result.context = path.resolve(argv.context);
43 | }
44 | // there is no else case for context, as we don't want a default value
45 | // here to override a context value in a config
46 |
47 | if (argv.debug) {
48 | const { LoaderOptionsPlugin } = webpack;
49 | const plugin = new LoaderOptionsPlugin({ debug: true });
50 | plugins.unshift(plugin);
51 | }
52 |
53 | if (argv.devtool) {
54 | result.devtool = argv.devtool;
55 | }
56 |
57 | if (argv.progress) {
58 | result.progress = argv.progress;
59 | }
60 |
61 | if (argv.reporter) {
62 | result.reporter = argv.reporter;
63 | }
64 |
65 | if (argv.watch) {
66 | result.watch = true;
67 | }
68 |
69 | return merge(options, result, plugins.length ? { plugins } : {});
70 | },
71 |
72 | flags: {
73 | context: {
74 | desc: 'The root directory for resolving entry point and stats',
75 | type: 'string',
76 | },
77 | debug: {
78 | desc: 'Switch loaders to debug mode',
79 | type: 'boolean',
80 | },
81 | devtool: {
82 | desc: chalk`Enable devtool for better debugging experience.
83 | {dim e.g. --devtool eval-cheap-module-source-map}`,
84 | type: 'string',
85 | },
86 | entry: {
87 | desc: 'The entry point',
88 | type: ['array', 'object', 'string'],
89 | },
90 | help: {
91 | desc: 'Show usage information and the options listed here',
92 | },
93 | 'log-level': {
94 | desc: chalk`Limit all process console messages to a specific level and above
95 | {dim Levels: trace, debug, info, warn, error, silent}`,
96 | type: 'string',
97 | },
98 | 'log-time': {
99 | desc: 'Instruct the logger and dependencies to display a timestamp',
100 | },
101 | progress: {
102 | desc: chalk`Instructs webpack to track and display build progress
103 | {dim This is often used with --profile}`,
104 | type: 'boolean',
105 | },
106 | reporter: {
107 | desc:
108 | 'Specifies the reporter to use for generating console output for a build',
109 | type: 'string',
110 | },
111 | require: {
112 | desc: `Preload one or more modules before loading the webpack configuration
113 | Typically used for language-specific require hooks`,
114 | type: ['string', 'array'],
115 | },
116 | 'run-dev': {
117 | alias: 'd',
118 | desc: `An alias for --debug --devtool eval-cheap-module-source-map
119 | --mode development --output-pathinfo`,
120 | type: 'boolean',
121 | },
122 | 'run-prod': {
123 | alias: 'p',
124 | desc: `An alias for --optimize-minimize --mode production, and defines
125 | process.env.NODE_ENV="production"`,
126 | type: 'boolean',
127 | },
128 | version: {
129 | desc: 'Display the webpack-command version',
130 | },
131 | watch: {
132 | alias: 'w',
133 | desc: 'Watch the filesystem for changes',
134 | type: 'boolean',
135 | },
136 | },
137 |
138 | name: 'General',
139 | };
140 |
--------------------------------------------------------------------------------
/test/tests/flags/__snapshots__/module-bind.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flags > --module-bind > should apply #0 1`] = `
4 | Object {
5 | "entry": "/test/fixtures/common/entry-a.js",
6 | "mode": "development",
7 | "module": Object {
8 | "rules": Array [
9 | Object {
10 | "enforce": undefined,
11 | "loader": "/test/fixtures/common/loader",
12 | "test": /\\\\\\.js\\$/,
13 | },
14 | ],
15 | },
16 | "plugins": Array [
17 | NamedModulesPlugin {
18 | "options": Object {},
19 | },
20 | ],
21 | "reporter": "/test/fixtures/common/test-reporter.js",
22 | }
23 | `;
24 |
25 | exports[`Flags > --module-bind > should bind and build #0 1`] = `
26 | "Version: webpack 4.14.0
27 | Asset Size Chunks Chunk Names
28 | main.js 3.93 KiB main [emitted] main
29 | Entrypoint main = main.js
30 | [./test/fixtures/common/entry-a.js] 49 bytes {main} [built]"
31 | `;
32 |
33 | exports[`Flags > --module-bind > should bind and build #1 1`] = `"7cd38dd8"`;
34 |
35 | exports[`Flags > --module-bind-all > should apply #0 1`] = `
36 | Object {
37 | "entry": "/test/fixtures/common/entry-a.js",
38 | "mode": "development",
39 | "module": Object {
40 | "rules": Array [
41 | Object {
42 | "enforce": undefined,
43 | "loader": "json-loader",
44 | "test": /\\\\\\.json\\$/,
45 | },
46 | Object {
47 | "enforce": "pre",
48 | "loader": "/test/fixtures/common/loader-pre",
49 | "test": /\\\\\\.js\\$/,
50 | },
51 | Object {
52 | "enforce": "post",
53 | "loader": "/test/fixtures/common/loader-post",
54 | "test": /\\\\\\.js\\$/,
55 | },
56 | ],
57 | },
58 | "plugins": Array [
59 | NamedModulesPlugin {
60 | "options": Object {},
61 | },
62 | ],
63 | "reporter": "/test/fixtures/common/test-reporter.js",
64 | }
65 | `;
66 |
67 | exports[`Flags > --module-bind-all > should bind and build #0 1`] = `
68 | "Version: webpack 4.14.0
69 | Asset Size Chunks Chunk Names
70 | main.js 3.96 KiB main [emitted] main
71 | Entrypoint main = main.js
72 | [./test/fixtures/common/entry-a.js] 78 bytes {main} [built]"
73 | `;
74 |
75 | exports[`Flags > --module-bind-all > should bind and build #1 1`] = `"4038280e"`;
76 |
77 | exports[`Flags > --module-bind-post > should apply #0 1`] = `
78 | Object {
79 | "entry": "/test/fixtures/common/entry-a.js",
80 | "mode": "development",
81 | "module": Object {
82 | "rules": Array [
83 | Object {
84 | "enforce": "post",
85 | "loader": "/test/fixtures/common/loader-post",
86 | "test": /\\\\\\.js\\$/,
87 | },
88 | ],
89 | },
90 | "plugins": Array [
91 | NamedModulesPlugin {
92 | "options": Object {},
93 | },
94 | ],
95 | "reporter": "/test/fixtures/common/test-reporter.js",
96 | }
97 | `;
98 |
99 | exports[`Flags > --module-bind-post > should bind and build #0 1`] = `
100 | "Version: webpack 4.14.0
101 | Asset Size Chunks Chunk Names
102 | main.js 3.94 KiB main [emitted] main
103 | Entrypoint main = main.js
104 | [./test/fixtures/common/entry-a.js] 60 bytes {main} [built]"
105 | `;
106 |
107 | exports[`Flags > --module-bind-post > should bind and build #1 1`] = `"8342acc8"`;
108 |
109 | exports[`Flags > --module-bind-pre > should apply #0 1`] = `
110 | Object {
111 | "entry": "/test/fixtures/common/entry-a.js",
112 | "mode": "development",
113 | "module": Object {
114 | "rules": Array [
115 | Object {
116 | "enforce": "pre",
117 | "loader": "/test/fixtures/common/loader-pre",
118 | "test": /\\\\\\.js\\$/,
119 | },
120 | ],
121 | },
122 | "plugins": Array [
123 | NamedModulesPlugin {
124 | "options": Object {},
125 | },
126 | ],
127 | "reporter": "/test/fixtures/common/test-reporter.js",
128 | }
129 | `;
130 |
131 | exports[`Flags > --module-bind-pre > should bind and build #0 1`] = `
132 | "Version: webpack 4.14.0
133 | Asset Size Chunks Chunk Names
134 | main.js 3.94 KiB main [emitted] main
135 | Entrypoint main = main.js
136 | [./test/fixtures/common/entry-a.js] 59 bytes {main} [built]"
137 | `;
138 |
139 | exports[`Flags > --module-bind-pre > should bind and build #1 1`] = `"59c523e"`;
140 |
--------------------------------------------------------------------------------
/lib/flags/advanced.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | const camelcase = require('camelcase');
4 | const chalk = require('chalk');
5 | const isObject = require('isobject');
6 | const merge = require('merge-options');
7 | const {
8 | DefinePlugin,
9 | HotModuleReplacementPlugin,
10 | PrefetchPlugin,
11 | ProvidePlugin,
12 | } = require('webpack');
13 |
14 | const { loadPlugin } = require('./util');
15 |
16 | module.exports = {
17 | apply(argv, options) {
18 | let plugins = [];
19 | const output = { watchOptions: {} };
20 |
21 | if (options.plugins) {
22 | plugins = plugins.concat(options.plugins);
23 | }
24 |
25 | for (const flag of ['bail', 'cache', 'profile', 'target']) {
26 | if (argv[flag]) {
27 | output[flag] = argv[flag];
28 | }
29 | }
30 |
31 | for (const name of [
32 | 'records-input-path',
33 | 'records-output-path',
34 | 'records-path',
35 | ]) {
36 | const flag = camelcase(name);
37 | if (argv[flag]) {
38 | output[flag] = resolve(argv[flag]);
39 | }
40 | }
41 |
42 | // --define.test ok
43 | if (argv.define && isObject(argv.define)) {
44 | const plugin = new DefinePlugin(argv.define);
45 | plugins.unshift(plugin);
46 | }
47 |
48 | if (argv.hot) {
49 | const plugin = new HotModuleReplacementPlugin();
50 | plugins.unshift(plugin);
51 | }
52 |
53 | if (argv.plugin) {
54 | const plugin = loadPlugin(argv.plugin);
55 | plugins.unshift(plugin);
56 | }
57 |
58 | if (argv.prefetch) {
59 | const plugin = new PrefetchPlugin(argv.prefetch);
60 | plugins.unshift(plugin);
61 | }
62 |
63 | if (argv.provide && isObject(argv.provide)) {
64 | const plugin = new ProvidePlugin(argv.provide);
65 | plugins.unshift(plugin);
66 | }
67 |
68 | if (argv.watchAggregateTimeout) {
69 | output.watchOptions.aggregateTimeout = +argv.watchAggregateTimeout;
70 | }
71 |
72 | if (argv.watchPoll) {
73 | const value =
74 | typeof argv.watchPoll === 'boolean' ? true : +argv.watchPoll;
75 | output.watchOptions.poll = value;
76 | }
77 |
78 | if (argv.watchStdin) {
79 | output.watchOptions.stdin = true;
80 | output.watch = true;
81 | }
82 |
83 | if (!Object.keys(output.watchOptions).length) {
84 | delete output.watchOptions;
85 | }
86 |
87 | const result = merge(options, output, plugins.length ? { plugins } : {});
88 |
89 | return result;
90 | },
91 |
92 | flags: {
93 | bail: {
94 | type: 'boolean',
95 | desc: 'Abort the compilation on first error',
96 | },
97 | cache: {
98 | type: 'boolean',
99 | desc: 'Enable in memory caching',
100 | },
101 | define: {
102 | type: 'object',
103 | desc: `Used to redefine or replace a variable or key in the bundle. Complex
104 | keys should be set in config. {dim e.g. --define.batman robin}`,
105 | },
106 | hot: {
107 | type: 'boolean',
108 | desc: 'Enables Hot Module Replacement',
109 | },
110 | plugin: {
111 | type: 'string',
112 | desc: 'Load this plugin',
113 | },
114 | prefetch: {
115 | desc: chalk`Prefetch this request
116 | {dim e.g. --prefetch ./file.js}`,
117 | type: 'string',
118 | },
119 | profile: {
120 | desc: 'Profile the compilation and include information in stats',
121 | type: 'boolean',
122 | },
123 | provide: {
124 | desc: chalk`Provide these modules as free vars in all modules
125 | {dim e.g. --provide.jQuery jquery}`,
126 | type: 'object',
127 | },
128 | 'records-input-path': {
129 | desc: 'Path to the records file (reading)',
130 | type: 'string',
131 | },
132 | 'records-output-path': {
133 | desc: 'Path to the records file (writing)',
134 | type: 'string',
135 | },
136 | 'records-path': {
137 | desc: 'Path to the records file',
138 | type: 'string',
139 | },
140 | target: {
141 | desc: 'The targeted execution environment',
142 | type: 'string',
143 | },
144 | 'watch-aggregate-timeout': {
145 | desc: 'Timeout for gathering changes while watching',
146 | type: ['string', 'number'],
147 | },
148 | 'watch-poll': {
149 | desc: 'The polling interval for watching (also enable polling)',
150 | type: ['string', 'number'],
151 | },
152 | 'watch-stdin': {
153 | alias: 'stdin',
154 | desc: 'Exit the process when stdin is closed',
155 | type: 'boolean',
156 | },
157 | },
158 |
159 | name: 'Advanced',
160 | };
161 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-command",
3 | "version": "0.4.1",
4 | "description": "A superior CLI experience for webpack. Lightweight, modular, and opinionated.",
5 | "license": "MIT",
6 | "repository": "webpack-contrib/webpack-command",
7 | "author": "Andrew Powell ",
8 | "homepage": "https://github.com/webpack-contrib/webpack-command",
9 | "bugs": "https://github.com/webpack-contrib/webpack-command/issues",
10 | "bin": {
11 | "webpack": "lib/cli.js",
12 | "webpack-command": "lib/cli.js",
13 | "wp": "lib/cli.js"
14 | },
15 | "main": "lib/index.js",
16 | "engines": {
17 | "node": ">= 6.9.0 <7.0.0 || >= 8.9.0"
18 | },
19 | "scripts": {
20 | "commitlint": "commitlint",
21 | "commitmsg": "commitlint -e $GIT_PARAMS",
22 | "lint": "eslint --cache lib test",
23 | "ci:lint:commits": "commitlint --from=${CIRCLE_BRANCH} --to=${CIRCLE_SHA1}",
24 | "lint-staged": "lint-staged",
25 | "prepublishOnly": "mkdir -p data && cp -r lib/commands/defaults.json data/commands.json",
26 | "release": "standard-version",
27 | "release:ci": "conventional-github-releaser -p angular",
28 | "release:validate": "commitlint --from=$(git describe --tags --abbrev=0) --to=$(git rev-parse HEAD)",
29 | "security": "nsp check",
30 | "test": "npm run prepublishOnly && mocha test/test.js --exit --timeout=5000",
31 | "test:coverage": "mkdir -p coverage && nyc --silent npm test && npm run test:coverage:report",
32 | "test:coverage:report": "nyc report --reporter=lcov --reporter=text-lcov --reporter=json --reporter=clover > coverage/lcov.info",
33 | "ci:lint": "npm run lint && npm run security",
34 | "ci:test": "npm run test -- --runInBand",
35 | "ci:coverage": "npm run test:coverage -- --runInBand",
36 | "defaults": "webpack-defaults"
37 | },
38 | "files": [
39 | "data/",
40 | "lib/"
41 | ],
42 | "peerDependencies": {
43 | "webpack": "^4.4.0"
44 | },
45 | "dependencies": {
46 | "@webpack-contrib/config-loader": "^1.2.0",
47 | "@webpack-contrib/schema-utils": "^1.0.0-beta.0",
48 | "camelcase": "^5.0.0",
49 | "chalk": "^2.3.2",
50 | "debug": "^3.1.0",
51 | "decamelize": "^2.0.0",
52 | "enhanced-resolve": "^4.0.0",
53 | "import-local": "^1.0.0",
54 | "isobject": "^3.0.1",
55 | "loader-utils": "^1.1.0",
56 | "log-symbols": "^2.2.0",
57 | "loud-rejection": "^1.6.0",
58 | "meant": "^1.0.1",
59 | "meow": "^5.0.0",
60 | "merge-options": "^1.0.0",
61 | "object.values": "^1.0.4",
62 | "opn": "^5.3.0",
63 | "ora": "^2.1.0",
64 | "plur": "^3.0.0",
65 | "pretty-bytes": "^5.0.0",
66 | "strip-ansi": "^4.0.0",
67 | "text-table": "^0.2.0",
68 | "titleize": "^1.0.1",
69 | "update-notifier": "^2.3.0",
70 | "v8-compile-cache": "^2.0.0",
71 | "webpack-log": "^1.1.2",
72 | "wordwrap": "^1.0.0"
73 | },
74 | "devDependencies": {
75 | "@commitlint/cli": "^6.1.3",
76 | "@commitlint/config-conventional": "^6.1.3",
77 | "@webpack-contrib/eslint-config-webpack": "^2.0.4",
78 | "babel-cli": "^6.26.0",
79 | "babel-jest": "^23.0.1",
80 | "babel-plugin-transform-object-rest-spread": "^6.26.0",
81 | "babel-polyfill": "^6.26.0",
82 | "babel-preset-env": "^1.6.1",
83 | "camelcase-keys": "^4.2.0",
84 | "codecov": "^3.0.0",
85 | "conventional-github-releaser": "^2.0.2",
86 | "crc": "^3.5.0",
87 | "cross-env": "^5.1.4",
88 | "decamelize-keys": "^1.1.0",
89 | "del": "^3.0.0",
90 | "del-cli": "^1.1.0",
91 | "eslint": "^4.19.1",
92 | "eslint-config-webpack": "^1.2.5",
93 | "eslint-plugin-import": "^2.8.0",
94 | "eslint-plugin-prettier": "^2.6.0",
95 | "execa": "^0.10.0",
96 | "expect": "^23.1.0",
97 | "html-webpack-plugin": "^3.2.0",
98 | "husky": "^0.14.3",
99 | "istanbul": "^0.4.5",
100 | "jest-serializer-path": "^0.1.14",
101 | "jest-snapshot": "^23.0.1",
102 | "lint-staged": "^7.0.4",
103 | "memory-fs": "^0.4.1",
104 | "minimist": "^1.2.0",
105 | "minimist-options": "^3.0.2",
106 | "mocha": "^5.1.1",
107 | "nsp": "^3.2.1",
108 | "nyc": "^12.0.2",
109 | "pre-commit": "^1.2.2",
110 | "prettier": "^1.11.1",
111 | "standard-version": "^4.3.0",
112 | "stylelint-webpack-plugin": "^0.10.4",
113 | "webpack": "^4.6.0",
114 | "webpack-defaults": "^2.3.0"
115 | },
116 | "keywords": [
117 | "webpack"
118 | ],
119 | "pre-commit": "lint-staged",
120 | "lint-staged": {
121 | "*.js": [
122 | "eslint --fix",
123 | "git add"
124 | ]
125 | },
126 | "nyc": {
127 | "include": [
128 | "lib/**/*.js"
129 | ]
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | unit_tests: &unit_tests
2 | steps:
3 | - checkout
4 | - restore_cache:
5 | key: dependency-cache-{{ checksum "package-lock.json" }}
6 | - run:
7 | name: NPM Rebuild
8 | command: npm install
9 | - run:
10 | name: Run unit tests.
11 | command: npm run ci:test
12 | canary_tests: &canary_tests
13 | steps:
14 | - checkout
15 | - restore_cache:
16 | key: dependency-cache-{{ checksum "package-lock.json" }}
17 | - run:
18 | name: NPM Rebuild
19 | command: npm install
20 | - run:
21 | name: Install Webpack Canary
22 | command: npm i --no-save webpack@next
23 | - run:
24 | name: Run unit tests.
25 | command: if [[ $(compver --name webpack --gte next --lt latest) < 1 ]] ; then printf "Next is older than Latest - Skipping Canary Suite"; else npm run ci:test ; fi
26 |
27 | version: 2
28 | jobs:
29 | dependency_cache:
30 | docker:
31 | - image: webpackcontrib/circleci-node-base:latest
32 | steps:
33 | - checkout
34 | - restore_cache:
35 | key: dependency-cache-{{ checksum "package-lock.json" }}
36 | - run:
37 | name: Install Dependencies
38 | command: npm install
39 | - save_cache:
40 | key: dependency-cache-{{ checksum "package-lock.json" }}
41 | paths:
42 | - ./node_modules
43 |
44 | node8-latest:
45 | docker:
46 | - image: webpackcontrib/circleci-node8:latest
47 | steps:
48 | - checkout
49 | - restore_cache:
50 | key: dependency-cache-{{ checksum "package-lock.json" }}
51 | - run:
52 | name: NPM Rebuild
53 | command: npm install
54 | - run:
55 | name: Run unit tests.
56 | command: npm run ci:coverage
57 | - run:
58 | name: Submit coverage data to codecov.
59 | command: bash <(curl -s https://codecov.io/bash)
60 | when: on_success
61 | node6-latest:
62 | docker:
63 | - image: webpackcontrib/circleci-node6:latest
64 | <<: *unit_tests
65 | node10-latest:
66 | docker:
67 | - image: webpackcontrib/circleci-node10:latest
68 | <<: *unit_tests
69 | node8-canary:
70 | docker:
71 | - image: webpackcontrib/circleci-node8:latest
72 | <<: *canary_tests
73 | analysis:
74 | docker:
75 | - image: webpackcontrib/circleci-node-base:latest
76 | steps:
77 | - checkout
78 | - restore_cache:
79 | key: dependency-cache-{{ checksum "package-lock.json" }}
80 | - run:
81 | name: NPM Rebuild
82 | command: npm install
83 | - run:
84 | name: Run linting.
85 | command: npm run lint
86 | - run:
87 | name: Run NSP Security Check.
88 | command: npm run security
89 | - run:
90 | name: Validate Commit Messages
91 | command: npm run ci:lint:commits
92 | publish:
93 | docker:
94 | - image: webpackcontrib/circleci-node-base:latest
95 | steps:
96 | - checkout
97 | - restore_cache:
98 | key: dependency-cache-{{ checksum "package-lock.json" }}
99 | - run:
100 | name: NPM Rebuild
101 | command: npm install
102 | # - run:
103 | # name: Validate Commit Messages
104 | # command: npm run release:validate
105 | - run:
106 | name: Publish to NPM
107 | command: printf "noop running conventional-github-releaser"
108 |
109 | version: 2.0
110 | workflows:
111 | version: 2
112 | validate-publish:
113 | jobs:
114 | - dependency_cache
115 | - node6-latest:
116 | requires:
117 | - dependency_cache
118 | filters:
119 | tags:
120 | only: /.*/
121 | - analysis:
122 | requires:
123 | - dependency_cache
124 | filters:
125 | tags:
126 | only: /.*/
127 | - node8-latest:
128 | requires:
129 | - analysis
130 | - node6-latest
131 | filters:
132 | tags:
133 | only: /.*/
134 | - node10-latest:
135 | requires:
136 | - analysis
137 | - node6-latest
138 | filters:
139 | tags:
140 | only: /.*/
141 | - node8-canary:
142 | requires:
143 | - analysis
144 | - node6-latest
145 | filters:
146 | tags:
147 | only: /.*/
148 | - publish:
149 | requires:
150 | - node8-latest
151 | - node8-canary
152 | - node10-latest
153 | filters:
154 | branches:
155 | only:
156 | - master
157 |
--------------------------------------------------------------------------------
/test/tests/reporters.js:
--------------------------------------------------------------------------------
1 | const strip = require('strip-ansi');
2 |
3 | const parse = require('../../lib/reporters/parse');
4 | const Reporter = require('../../lib/reporters/Reporter');
5 | const { apply, build, test, validate } = require('../util');
6 |
7 | test('reporter parse util', module, () => {
8 | it('should parse hidden', () => {
9 | const stats = {
10 | filteredAssets: 1,
11 | filteredModules: 2,
12 | };
13 | const result = parse.hidden(stats);
14 |
15 | expect(result).toMatchSnapshot();
16 | });
17 |
18 | it('should parse status: cacheable', () => {
19 | const result = parse.status({ cacheable: false });
20 |
21 | expect(result).toMatchSnapshot();
22 | });
23 |
24 | it('should parse status: optional', () => {
25 | const result = parse.status({ optional: true });
26 |
27 | expect(result).toMatchSnapshot();
28 | });
29 |
30 | it('should parse status: prefetched', () => {
31 | const result = parse.status({ prefetched: true });
32 |
33 | expect(result).toMatchSnapshot();
34 | });
35 | });
36 |
37 | test('Reporter', module, () => {
38 | it('should have methods', () => {
39 | expect(Reporter).toBeDefined();
40 |
41 | const reporter = new Reporter({ compiler: {}, config: {} });
42 |
43 | expect(reporter).toBeInstanceOf(Reporter);
44 | expect(reporter.compiler).toBeDefined();
45 | expect(reporter.config).toBeDefined();
46 | expect(reporter.progress).toBeDefined();
47 | expect(reporter.render).toBeDefined();
48 |
49 | expect(reporter.progress()).toBeUndefined();
50 | expect(reporter.render()).toBeUndefined();
51 | });
52 | });
53 |
54 | test('StylishReporter', module, () => {
55 | for (const name of [
56 | 'stylish',
57 | 'stylish-multi',
58 | 'problems/stylish-problems',
59 | ]) {
60 | const fixture = `stylish/${name}`;
61 | const fixtureType = 'reporters';
62 | const opts = { fixture, fixtureType };
63 |
64 | let config;
65 |
66 | it(`${name}: reporter should validate`, () => {
67 | expect(validate(opts)).toEqual(true);
68 | });
69 |
70 | it(`${name}: reporter should apply`, () => {
71 | config = apply(opts);
72 |
73 | expect(config).toMatchSnapshot();
74 | });
75 |
76 | it(`${name}: reporter should build`, () =>
77 | build(config).then((result) => {
78 | expect(
79 | strip(result)
80 | .replace(/Δt \d+ms/g, '')
81 | .replace(/\d+\.\d+ (KiB|kB)/g, '')
82 | .replace(/[a-f0-9]{20}/g, '')
83 | ).toMatchSnapshot();
84 | }));
85 | }
86 | });
87 |
88 | test('JsonReporter', module, () => {
89 | for (const name of ['json', 'json-multi', 'problems/problems']) {
90 | const fixture = `json/${name}`;
91 | const fixtureType = 'reporters';
92 | const opts = { fixture, fixtureType };
93 |
94 | let config;
95 |
96 | it(`${name}: reporter should validate`, () => {
97 | expect(validate(opts)).toEqual(true);
98 | });
99 |
100 | it(`${name}: reporter should apply`, () => {
101 | config = apply(opts);
102 |
103 | expect(config).toMatchSnapshot();
104 | });
105 |
106 | it(`${name}: reporter should build`, () =>
107 | build(config).then((result) => {
108 | expect(result.length).toBeGreaterThan(0);
109 |
110 | const json = JSON.parse(result);
111 |
112 | expect(Object.keys(json).length).toBeGreaterThan(0);
113 |
114 | if (name === 'problems/problems') {
115 | expect(json.errors.length).toBeGreaterThan(0);
116 | expect(json.warnings.length).toBeGreaterThan(0);
117 | }
118 | }));
119 | }
120 | });
121 |
122 | test('reporters + bail', module, () => {
123 | for (const name of ['Basic', 'Json', 'Stylish']) {
124 | it(`${name}: render should return error when bail set`, () => {
125 | const reporterPath = `../../lib/reporters/${name}Reporter`;
126 | // eslint-disable-next-line global-require, import/no-dynamic-require
127 | const ReporterClass = require(reporterPath);
128 | const reporter = new ReporterClass({});
129 | const error = new Error('test');
130 | expect(reporter.render(error, null)).toMatchSnapshot();
131 | });
132 | }
133 | });
134 |
135 | test('bad reporter name', module, () => {
136 | const fixture = `json/json`;
137 | const fixtureType = 'reporters';
138 | const opts = { fixture, fixtureType };
139 |
140 | let config;
141 |
142 | it(`should apply`, () => {
143 | config = apply(opts);
144 | config.reporter = 'batman';
145 | expect(config).toMatchSnapshot();
146 | });
147 |
148 | it(`should default to stylish`, () =>
149 | build(config).then((result) => {
150 | expect(result.length).toBeGreaterThan(0);
151 | expect(
152 | strip(result)
153 | .replace(/Δt \d+ms/g, '')
154 | .replace(/\d+\.\d+ (KiB|kB)/g, '')
155 | .replace(/[a-f0-9]{20}/g, '')
156 | ).toMatchSnapshot();
157 | }));
158 | });
159 |
--------------------------------------------------------------------------------