Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(webpack-cli): allow multiple entry files #1619

Merged
merged 10 commits into from
Jun 17, 2020
2 changes: 1 addition & 1 deletion packages/webpack-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Available Commands

Options

--entry string The entry point of your application.
--entry string[] The entry point(s) of your application.
-c, --config string Provide path to a webpack configuration file
-m, --merge string Merge a configuration file using webpack-merge
--progress Print compilation progress during build
Expand Down
19 changes: 18 additions & 1 deletion packages/webpack-cli/__tests__/arg-parser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ const basicOptions = [
},
description: 'custom type flag',
},
{
name: 'multi-flag',
usage: '--multi-flag <value>',
type: String,
multiple: true,
description: 'multi flag',
},
];

const helpAndVersionOptions = basicOptions.slice(0);
Expand Down Expand Up @@ -163,6 +170,16 @@ describe('arg-parser', () => {
expect(warnMock.mock.calls.length).toEqual(0);
});

it('handles multiple same args', () => {
const res = argParser(basicOptions, ['--multi-flag', 'a.js', '--multi-flag', 'b.js'], true);
expect(res.unknownArgs.length).toEqual(0);
expect(res.opts).toEqual({
multiFlag: ['a.js', 'b.js'],
stringFlagWithDefault: 'default-value',
});
expect(warnMock.mock.calls.length).toEqual(0);
});

it('handles additional node args from argv', () => {
const res = argParser(basicOptions, ['node', 'index.js', '--bool-flag', '--string-flag', 'val'], false);
expect(res.unknownArgs.length).toEqual(0);
Expand Down Expand Up @@ -210,7 +227,7 @@ describe('arg-parser', () => {
it('parses webpack args', () => {
const res = argParser(core, ['--entry', 'test.js', '--hot', '-o', './dist/'], true);
expect(res.unknownArgs.length).toEqual(0);
expect(res.opts.entry).toEqual('test.js');
expect(res.opts.entry).toEqual(['test.js']);
expect(res.opts.hot).toBeTruthy();
expect(res.opts.output).toEqual('./dist/');
expect(warnMock.mock.calls.length).toEqual(0);
Expand Down
21 changes: 14 additions & 7 deletions packages/webpack-cli/lib/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,21 @@ async function runCLI(cli, commandIsUsed) {
// if the unknown arg starts with a '-', it will be considered
// an unknown flag rather than an entry
let entry;
if (parsedArgs.unknownArgs.length === 1 && !parsedArgs.unknownArgs[0].startsWith('-')) {
entry = parsedArgs.unknownArgs[0];
} else if (parsedArgs.unknownArgs.length > 0) {
parsedArgs.unknownArgs
.filter((e) => e)
.forEach((unknown) => {
logger.warn('Unknown argument:', unknown);
if (parsedArgs.unknownArgs.length > 0 && !parsedArgs.unknownArgs[0].startsWith('-')) {
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
if (parsedArgs.unknownArgs.length === 1) {
entry = parsedArgs.unknownArgs[0];
} else {
entry = [];
parsedArgs.unknownArgs.forEach((unknown) => {
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
if (!unknown.startsWith('-')) {
entry.push(unknown);
}
});
}
} else if (parsedArgs.unknownArgs.length > 0) {
parsedArgs.unknownArgs.forEach((unknown) => {
logger.warn('Unknown argument:', unknown);
});
cliExecuter();
return;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/webpack-cli/lib/groups/BasicGroup.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const GroupHelper = require('../utils/GroupHelper');
const chalk = require('chalk');
const { core, groups } = require('../utils/cli-flags');

class BasicGroup extends GroupHelper {
Expand Down Expand Up @@ -35,6 +36,9 @@ class BasicGroup extends GroupHelper {
}
if (arg === 'entry') {
options[arg] = this.resolveFilePath(args[arg], 'index.js');
if (options[arg].length === 0) {
process.stdout.write(chalk.red('\nError: you provided an invalid entry point.\n'));
}
}
});
if (outputOptions['dev']) {
Expand Down
7 changes: 6 additions & 1 deletion packages/webpack-cli/lib/utils/arg-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@ function argParser(options, args, argsOnly = false, name = '', helpFunction = un
const flags = option.alias ? `-${option.alias}, --${option.name}` : `--${option.name}`;
const flagsWithType = option.type !== Boolean ? flags + ' <value>' : flags;
if (option.type === Boolean || option.type === String) {
parserInstance.option(flagsWithType, option.description, option.defaultValue);
if (!option.multiple) {
parserInstance.option(flagsWithType, option.description, option.defaultValue);
} else {
const multiArg = (value, previous = []) => previous.concat([value]);
parserInstance.option(flagsWithType, option.description, multiArg, option.defaultValue);
}
} else {
// in this case the type is a parsing function
parserInstance.option(flagsWithType, option.description, option.type, option.defaultValue);
Expand Down
5 changes: 3 additions & 2 deletions packages/webpack-cli/lib/utils/cli-flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@ module.exports = {
core: [
{
name: 'entry',
usage: '--entry <path to entry file>',
usage: '--entry <path to entry file> | --entry <path> --entry <path>',
type: String,
multiple: true,
defaultOption: true,
group: BASIC_GROUP,
description: 'The entry point of your application e.g. ./src/main.js',
description: 'The entry point(s) of your application e.g. ./src/main.js',
link: 'https://webpack.js.org/concepts/#entry',
},
{
Expand Down
4 changes: 2 additions & 2 deletions test/entry/flag-entry/entry-with-flag.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('entry flag', () => {

it('should throw error for invalid entry file', () => {
const { stderr, stdout } = run(__dirname, ['--entry', './src/test.js']);
expect(stderr).toBeFalsy();
expect(stdout).toContain('not found');
expect(stderr).toBeTruthy();
expect(stdout).toContain('Error: you provided an invalid entry point.');
});
});
43 changes: 43 additions & 0 deletions test/entry/multiple-entries/multi-entries.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use strict';

const { run } = require('../../utils/test-utils');
const { stat, readFile } = require('fs');
const { resolve } = require('path');

describe(' multiple entries', () => {
it('should allow multiple entry files', (done) => {
const { stderr, stdout } = run(__dirname, ['./src/a.js', './src/b.js']);
expect(stderr).toBeFalsy();
expect(stdout).toBeTruthy();

stat(resolve(__dirname, './bin/main.js'), (err, stats) => {
expect(err).toBe(null);
expect(stats.isFile()).toBe(true);
done();
});
readFile(resolve(__dirname, './bin/main.js'), 'utf-8', (err, data) => {
expect(err).toBe(null);
expect(data).toContain('Hello from a.js');
expect(data).toContain('Hello from b.js');
done();
});
});

it('should allow multiple entry flags', (done) => {
const { stderr, stdout } = run(__dirname, ['--entry', 'src/a.js', '--entry', 'src/b.js']);
expect(stderr).toBeFalsy();
expect(stdout).toBeTruthy();

stat(resolve(__dirname, './bin/main.js'), (err, stats) => {
expect(err).toBe(null);
expect(stats.isFile()).toBe(true);
done();
});
readFile(resolve(__dirname, './bin/main.js'), 'utf-8', (err, data) => {
expect(err).toBe(null);
expect(data).toContain('Hello from a.js');
expect(data).toContain('Hello from b.js');
done();
});
});
});
1 change: 1 addition & 0 deletions test/entry/multiple-entries/src/a.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('Hello from a.js');
1 change: 1 addition & 0 deletions test/entry/multiple-entries/src/b.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('Hello from b.js');
1 change: 1 addition & 0 deletions test/entry/multiple-entries/src/c.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('Hello from c.js');
1 change: 0 additions & 1 deletion test/init/auto/init-auto.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const { run } = require('../../utils/test-utils');
const firstPrompt = 'Will your application have multiple bundles?';
const genPath = join(__dirname, 'test-assets');

jest.setTimeout(60000);
describe('init auto flag', () => {
beforeAll(() => {
rimraf.sync(genPath);
Expand Down
2 changes: 0 additions & 2 deletions test/init/force/init-force.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ const firstPrompt = 'Will your application have multiple bundles?';
const ENTER = '\x0D';
const genPath = join(__dirname, 'test-assets');

jest.setTimeout(100000);

describe('init force flag', () => {
beforeAll(() => {
rimraf.sync(genPath);
Expand Down
2 changes: 0 additions & 2 deletions test/init/generator/init-inquirer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ const firstPrompt = 'Will your application have multiple bundles?';
const ENTER = '\x0D';
const genPath = join(__dirname, 'test-assets');

jest.setTimeout(100000);

describe('init', () => {
beforeAll(() => {
rimraf.sync(genPath);
Expand Down
2 changes: 0 additions & 2 deletions test/init/multipleEntries/init-multipleEntries.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ const firstPrompt = 'Will your application have multiple bundles?';
const ENTER = '\x0D';
const genPath = path.join(__dirname, 'test-assets');

jest.setTimeout(100000);

describe('init with multiple entries', () => {
beforeAll(() => {
rimraf.sync(genPath);
Expand Down