Skip to content

Commit

Permalink
Merge branch 'next' into utils/cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
anshumanv authored Jul 1, 2020
2 parents bfdb64c + 28526a6 commit c62a701
Show file tree
Hide file tree
Showing 36 changed files with 431 additions and 107 deletions.
22 changes: 16 additions & 6 deletions INIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,21 @@

`webpack-cli init` is used to initialize `webpack` projects quickly by scaffolding configuration and creating a runnable project with all the dependencies based on the user preferences.

## Table of Contents

- [Initial Setup](#initial-setup)
- [Local Setup](#local-setup)
- [Global Setup](#global-setup)
- [Usage](#usage)
- [Running Globally](#running-globally)
- [Running Locally](#running-locally)
- [Description of questions asked by generator](#description-of-questions-asked-by-generator)

## Initial Setup

### a. Local setup
### a. Local Setup

These are the steps necessary to setup `webpack-cli init` locally:
These are the steps necessary to set up `webpack-cli init` locally:

1. Create `package.json` through npm

Expand All @@ -28,7 +38,7 @@ These are the steps necessary to setup `webpack-cli init` locally:

### b. Global Setup

These are the steps necessary to setup `webpack-cli init` globally:
These are the steps necessary to set up `webpack-cli init` globally:

1. Install `webpack` and `webpack-cli` globally

Expand All @@ -44,19 +54,19 @@ These are the steps necessary to setup `webpack-cli init` globally:

## Usage

### a. Running locally
### a. Running Locally

```shell
npx webpack-cli init
```

### b. Running globally
### b. Running Globally

```shell
webpack-cli init
```

### Description of questions asked by generator
### Description of questions asked by the generator

1. `Will your application have multiple bundles? (y/N)`

Expand Down
11 changes: 11 additions & 0 deletions MIGRATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ The `webpack-cli migrate` feature eases the transition from:

`webpack-cli migrate` also allows users to switch to the new version of webpack without having to do it extensively.

## Table of Contents

- [Installation](#installation)
- [Local Setup](#local-setup)
- [Global Setup](#global-setup)
- [Usage](#usage)
- [Local Setup](#local-setup)
- [Global Setup](#global-setup)
- [Usage Example](#usage-example)
- [Changes reflected after migration](#changes-reflected-after-migration)

## Installation

> Requires installation of `webpack` and `webpack-cli`
Expand Down
1 change: 1 addition & 0 deletions packages/webpack-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Options
-v, --version Get current version
--node-args string[] NodeJS flags
--stats string It instructs webpack on how to treat the stats
--no-stats Disables stats output
--verbose It tells webpack to output all the information
```

Expand Down
136 changes: 63 additions & 73 deletions packages/webpack-cli/lib/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@ require('./utils/process-log');

process.title = 'webpack-cli';

// const isFlagPresent = (args, flag) => args.find((arg) => [flag, `--${flag}`].includes(arg));
const isArgCommandName = (arg, cmd) => arg === cmd.name || arg === cmd.alias;
const removeCmdFromArgs = (args, cmd) => args.filter((arg) => !isArgCommandName(arg, cmd));
const normalizeFlags = (args, cmd) => {
const slicedArgs = args.slice(2);
return removeCmdFromArgs(slicedArgs, cmd);
};

const isCommandUsed = (commands) =>
commands.find((cmd) => {
return process.argv.includes(cmd.name) || process.argv.includes(cmd.alias);
Expand All @@ -25,7 +17,7 @@ async function runCLI(cli, commandIsUsed) {
const runVersion = () => {
cli.runVersion(process.argv, commandIsUsed);
};
const parsedArgs = argParser(core, process.argv, false, process.title, cli.runHelp, runVersion);
const parsedArgs = argParser(core, process.argv, false, process.title, cli.runHelp, runVersion, commands);

if (parsedArgs.unknownArgs.includes('help')) {
cli.runHelp(process.argv);
Expand All @@ -38,74 +30,72 @@ async function runCLI(cli, commandIsUsed) {
}

if (commandIsUsed) {
commandIsUsed.defaultOption = true;
args = normalizeFlags(process.argv, commandIsUsed);
return await cli.runCommand(commandIsUsed, ...args);
} else {
try {
// handle the default webpack entry CLI argument, where instead
// of doing 'webpack-cli --entry ./index.js' you can simply do
// 'webpack-cli ./index.js'
// if the unknown arg starts with a '-', it will be considered
// an unknown flag rather than an entry
let entry;
if (parsedArgs.unknownArgs.length > 0 && !parsedArgs.unknownArgs[0].startsWith('-')) {
if (parsedArgs.unknownArgs.length === 1) {
entry = parsedArgs.unknownArgs[0];
} else {
entry = [];
parsedArgs.unknownArgs.forEach((unknown) => {
if (!unknown.startsWith('-')) {
entry.push(unknown);
}
});
}
} else if (parsedArgs.unknownArgs.length > 0) {
return;
}

try {
// handle the default webpack entry CLI argument, where instead
// of doing 'webpack-cli --entry ./index.js' you can simply do
// 'webpack-cli ./index.js'
// if the unknown arg starts with a '-', it will be considered
// an unknown flag rather than an entry
let entry;
if (parsedArgs.unknownArgs.length > 0 && !parsedArgs.unknownArgs[0].startsWith('-')) {
if (parsedArgs.unknownArgs.length === 1) {
entry = parsedArgs.unknownArgs[0];
} else {
entry = [];
parsedArgs.unknownArgs.forEach((unknown) => {
logger.warn('Unknown argument:', unknown);
});
cliExecuter();
return;
}
const parsedArgsOpts = parsedArgs.opts;
if (entry) {
parsedArgsOpts.entry = entry;
}
const result = await cli.run(parsedArgsOpts, core);
if (!result) {
return;
}
} catch (err) {
if (err.name === 'UNKNOWN_VALUE') {
logger.error(`Parse Error (unknown argument): ${err.value}`);
return;
} else if (err.name === 'ALREADY_SET') {
const argsMap = {};
const keysToDelete = [];
process.argv.forEach((arg, idx) => {
const oldMapValue = argsMap[arg];
argsMap[arg] = {
value: process.argv[idx],
pos: idx,
};
// Swap idx of overridden value
if (oldMapValue) {
argsMap[arg].pos = oldMapValue.pos;
keysToDelete.push(idx + 1);
if (!unknown.startsWith('-')) {
entry.push(unknown);
}
});
// Filter out the value for the overridden key
const newArgKeys = Object.keys(argsMap).filter((arg) => !keysToDelete.includes(argsMap[arg].pos));
// eslint-disable-next-line require-atomic-updates
process.argv = newArgKeys;
args = argParser('', core, process.argv);
await cli.run(args.opts, core);
process.stdout.write('\n');
logger.warn('Duplicate flags found, defaulting to last set value');
} else {
logger.error(err);
return;
}
} else if (parsedArgs.unknownArgs.length > 0) {
parsedArgs.unknownArgs.forEach((unknown) => {
logger.warn('Unknown argument:', unknown);
});
cliExecuter();
return;
}
const parsedArgsOpts = parsedArgs.opts;
if (entry) {
parsedArgsOpts.entry = entry;
}
const result = await cli.run(parsedArgsOpts, core);
if (!result) {
return;
}
} catch (err) {
if (err.name === 'UNKNOWN_VALUE') {
logger.error(`Parse Error (unknown argument): ${err.value}`);
return;
} else if (err.name === 'ALREADY_SET') {
const argsMap = {};
const keysToDelete = [];
process.argv.forEach((arg, idx) => {
const oldMapValue = argsMap[arg];
argsMap[arg] = {
value: process.argv[idx],
pos: idx,
};
// Swap idx of overridden value
if (oldMapValue) {
argsMap[arg].pos = oldMapValue.pos;
keysToDelete.push(idx + 1);
}
});
// Filter out the value for the overridden key
const newArgKeys = Object.keys(argsMap).filter((arg) => !keysToDelete.includes(argsMap[arg].pos));
// eslint-disable-next-line require-atomic-updates
process.argv = newArgKeys;
args = argParser('', core, process.argv);
await cli.run(args.opts, core);
process.stdout.write('\n');
logger.warn('Duplicate flags found, defaulting to last set value');
} else {
logger.error(err);
return;
}
}
}
Expand Down
21 changes: 17 additions & 4 deletions packages/webpack-cli/lib/groups/ConfigGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,28 @@ const { extensions } = require('interpret');
const GroupHelper = require('../utils/GroupHelper');
const rechoir = require('rechoir');

// Order defines the priority, in increasing order
// example - config file lookup will be in order of .webpack/webpack.config.development.js -> webpack.config.development.js -> webpack.config.js
const DEFAULT_CONFIG_LOC = [
'webpack.config',
'webpack.config.dev',
'webpack.config.development',
'webpack.config.prod',
'webpack.config.production',
'.webpack/webpack.config',
'.webpack/webpack.config.none',
'.webpack/webpack.config.dev',
'.webpack/webpack.config.development',
'.webpack/webpack.config.prod',
'.webpack/webpack.config.production',
'.webpack/webpackfile',
'webpack.config',
];

const modeAlias = {
production: 'prod',
development: 'dev',
};

const fileTypes = {
'.babel.js': ['@babel/register', 'babel-register', 'babel-core/register', 'babel/register'],
'.babel.ts': ['@babel/register'],
Expand Down Expand Up @@ -136,10 +150,9 @@ class ConfigGroup extends GroupHelper {

const configFiles = tmpConfigFiles.map(this.requireConfig.bind(this));
if (configFiles.length) {
const defaultConfig = configFiles.find((p) => p.path.includes(mode));
const defaultConfig = configFiles.find((p) => p.path.includes(mode) || p.path.includes(modeAlias[mode]));
if (defaultConfig) {
const envConfig = defaultConfig.map((c) => c.content);
this.opts = this.finalize(envConfig);
this.opts = this.finalize(defaultConfig);
return;
}
const foundConfig = configFiles.pop();
Expand Down
2 changes: 1 addition & 1 deletion packages/webpack-cli/lib/groups/StatsGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const logger = require('../utils/logger');
*/
class StatsGroup extends GroupHelper {
static validOptions() {
return ['none', 'errors-only', 'minimal', 'normal', 'detailed', 'verbose', 'errors-warnings', true];
return ['none', 'errors-only', 'minimal', 'normal', 'detailed', 'verbose', 'errors-warnings', true, false];
}

constructor(options) {
Expand Down
39 changes: 34 additions & 5 deletions packages/webpack-cli/lib/utils/arg-parser.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
const commander = require('commander');
const logger = require('./logger');

const defaultCommands = {
init: 'init',
loader: 'generate-loader',
plugin: 'generate-plugin',
info: 'info',
migrate: 'migrate',
serve: 'serve',
};

/**
* Creates Argument parser corresponding to the supplied options
* parse the args and return the result
Expand All @@ -10,11 +19,30 @@ const logger = require('./logger');
* @param {boolean} argsOnly false if all of process.argv has been provided, true if
* args is only a subset of process.argv that removes the first couple elements
*/
function argParser(options, args, argsOnly = false, name = '', helpFunction = undefined, versionFunction = undefined) {
function argParser(options, args, argsOnly = false, name = '', helpFunction = undefined, versionFunction = undefined, commands) {
const parser = new commander.Command();
// Set parser name
parser.name(name);

if (commands) {
commands.reduce((parserInstance, cmd) => {
parser
.command(cmd.name)
.alias(cmd.alias)
.description(cmd.description)
.usage(cmd.usage)
.allowUnknownOption(true)
.action(async () => {
const cliArgs = args.slice(args.indexOf(cmd.name) + 1 || args.indexOf(cmd.alias) + 1);
return await require('../commands/ExternalCommand').run(defaultCommands[cmd.name], ...cliArgs);
});
return parser;
}, parser);

// Prevent default behavior
parser.on('command:*', () => {});
}

// Use customized version output if available
if (versionFunction) {
parser.on('option:version', () => {
Expand All @@ -40,20 +68,21 @@ function argParser(options, args, argsOnly = false, name = '', helpFunction = un
let flagsWithType = option.type !== Boolean ? flags + ' <value>' : flags;
if (option.type === Boolean || option.type === String) {
if (!option.multiple) {
parserInstance.option(flagsWithType, option.description, option.defaultValue);
// Prevent default behavior for standalone options
parserInstance.option(flagsWithType, option.description, option.defaultValue).action(() => {});
} else {
const multiArg = (value, previous = []) => previous.concat([value]);
parserInstance.option(flagsWithType, option.description, multiArg, option.defaultValue);
parserInstance.option(flagsWithType, option.description, multiArg, option.defaultValue).action(() => {});
}
} else if (option.type === Number) {
parserInstance.option(flagsWithType, option.description, Number, option.defaultValue);
} else {
// in this case the type is a parsing function
if (option.type.length > 1) {
flagsWithType = flags + ' [value]';
parserInstance.option(flagsWithType, option.description, option.type[0], option.defaultValue);
parserInstance.option(flagsWithType, option.description, option.type[0], option.defaultValue).action(() => {});
} else {
parserInstance.option(flagsWithType, option.description, option.type, option.defaultValue);
parserInstance.option(flagsWithType, option.description, option.type, option.defaultValue).action(() => {});
}
}

Expand Down
8 changes: 8 additions & 0 deletions packages/webpack-cli/lib/utils/cli-flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,14 @@ module.exports = {
description: 'It instructs webpack on how to treat the stats e.g. verbose',
link: 'https://webpack.js.org/configuration/stats/#stats',
},
{
name: 'no-stats',
usage: '--no-stats',
type: Boolean,
group: DISPLAY_GROUP,
description: 'Disables stats output',
link: 'https://webpack.js.org/configuration/stats/#stats',
},
{
name: 'verbose',
usage: '--verbose',
Expand Down
Loading

0 comments on commit c62a701

Please sign in to comment.