Skip to content

Commit 09bd812

Browse files
authored
fix: resplect color/--no-color arguments (#2042)
1 parent 3965dcb commit 09bd812

File tree

11 files changed

+157
-13
lines changed

11 files changed

+157
-13
lines changed

packages/serve/__tests__/__snapshots__/parseArgs.test.ts.snap

-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ Object {
1010
"serveIndex": true,
1111
},
1212
"webpackArgs": Object {
13-
"color": true,
1413
"env": Object {
1514
"WEBPACK_SERVE": true,
1615
},
@@ -41,7 +40,6 @@ Object {
4140
"serveIndex": true,
4241
},
4342
"webpackArgs": Object {
44-
"color": true,
4543
"env": Object {
4644
"WEBPACK_SERVE": true,
4745
},

packages/webpack-cli/lib/bootstrap.js

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const logger = require('./utils/logger');
44
const { isCommandUsed } = require('./utils/arg-utils');
55
const argParser = require('./utils/arg-parser');
66
const leven = require('leven');
7+
const { options: coloretteOptions } = require('colorette');
78

89
process.title = 'webpack-cli';
910

@@ -23,6 +24,11 @@ const runCLI = async (cliArgs) => {
2324
// If the unknown arg starts with a '-', it will be considered an unknown flag rather than an entry
2425
let entry;
2526

27+
// enable/disable colors
28+
if (typeof parsedArgs.opts.color !== 'undefined') {
29+
coloretteOptions.enabled = Boolean(parsedArgs.opts.color);
30+
}
31+
2632
if (parsedArgs.unknownArgs.length > 0) {
2733
entry = [];
2834

packages/webpack-cli/lib/utils/cli-flags.js

-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ const core = [
109109
usage: '--color',
110110
type: Boolean,
111111
negative: true,
112-
defaultValue: true,
113112
description: 'Enable/Disable colors on console',
114113
},
115114
{

packages/webpack-cli/lib/webpack-cli.js

+17-3
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ class WebpackCLI {
4747
}
4848

4949
async resolveArgs(args, configOptions = {}) {
50-
// Since color flag has a default value, when there are no other args then exit
50+
// when there are no args then exit
5151
// eslint-disable-next-line no-prototype-builtins
52-
if (Object.keys(args).length === 1 && args.hasOwnProperty('color') && !process.env.NODE_ENV) return {};
52+
if (Object.keys(args).length === 0 && !process.env.NODE_ENV) return {};
5353

5454
const { outputPath, stats, json, mode, target, prefetch, hot, analyze } = args;
5555
const finalOptions = {
@@ -367,7 +367,21 @@ class WebpackCLI {
367367
}
368368
}
369369

370-
stats.colors = typeof stats.colors !== 'undefined' ? stats.colors : coloretteOptions.enabled;
370+
let colors;
371+
// From flags
372+
if (typeof args.color !== 'undefined') {
373+
colors = args.color;
374+
}
375+
// From stats
376+
else if (typeof stats.colors !== 'undefined') {
377+
colors = stats.colors;
378+
}
379+
// Default
380+
else {
381+
colors = coloretteOptions.enabled;
382+
}
383+
384+
stats.colors = colors;
371385

372386
return stats;
373387
};

test/colors/colors.test.js

+54-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,25 @@ describe('colorts', () => {
4343
expect(exitCode).toBe(0);
4444
});
4545

46+
it('should disable colored output with --no-color', () => {
47+
const { stderr, stdout, exitCode } = run(__dirname, ['--stats=verbose', '--no-color']);
48+
49+
expect(stderr).toBeFalsy();
50+
const output = isWebpack5 ? 'successfully' : 'main.js';
51+
expect(stdout).not.toContain(`\u001b[1m\u001b[32m${output}\u001b[39m\u001b[22m`);
52+
expect(stdout).toContain(output);
53+
expect(exitCode).toBe(0);
54+
});
55+
56+
it('should work with the "stats" option and --color flags', () => {
57+
const { stderr, stdout, exitCode } = run(__dirname, ['--stats=verbose', '--color']);
58+
59+
expect(stderr).toBeFalsy();
60+
const output = isWebpack5 ? 'successfully' : 'main.js';
61+
expect(stdout).toContain(`\u001b[1m\u001b[32m${output}\u001b[39m\u001b[22m`);
62+
expect(exitCode).toBe(0);
63+
});
64+
4665
it('should work with the "stats" option from the configuration', () => {
4766
const { stderr, stdout, exitCode } = run(__dirname, ['--config=stats-string.webpack.config.js']);
4867

@@ -84,9 +103,43 @@ describe('colorts', () => {
84103

85104
expect(stderr).toBeFalsy();
86105
const output = isWebpack5 ? 'successfully' : 'main.js';
87-
console.log(stdout);
106+
88107
expect(stdout).not.toContain(`\u001b[1m\u001b[32m${output}\u001b[39m\u001b[22m`);
89108
expect(stdout).toContain(output);
90109
expect(exitCode).toBe(0);
91110
});
111+
112+
it('should prioritize --color over colors in config', () => {
113+
const { stderr, stdout, exitCode } = run(__dirname, ['--config=colors-false.webpack.config.js', '--color']);
114+
115+
expect(stderr).toBeFalsy();
116+
const output = isWebpack5 ? 'successfully' : 'main.js';
117+
118+
expect(stdout).toContain(`\u001b[1m\u001b[32m${output}\u001b[39m\u001b[22m`);
119+
expect(exitCode).toBe(0);
120+
});
121+
122+
it('should prioratize --no-color over colors in config', () => {
123+
const { stderr, stdout, exitCode } = run(__dirname, ['--config=colors-true.webpack.config.js', '--no-color']);
124+
125+
expect(stderr).toBeFalsy();
126+
const output = isWebpack5 ? 'successfully' : 'main.js';
127+
128+
expect(stdout).not.toContain(`\u001b[1m\u001b[32m${output}\u001b[39m\u001b[22m`);
129+
expect(stdout).toContain(output);
130+
expect(exitCode).toBe(0);
131+
});
132+
133+
it('should work in multicompiler mode', () => {
134+
const { stderr, stdout, exitCode } = run(__dirname, ['--config=multiple-configs.js', '--color']);
135+
136+
expect(stderr).toBeFalsy();
137+
expect(exitCode).toBe(0);
138+
139+
if (isWebpack5) {
140+
expect(stdout).toContain(`\u001b[1mfirst-config`);
141+
expect(stdout).toContain(`\u001b[1msecond-config`);
142+
expect(stdout).toContain(`\u001b[1m\u001b[32msuccessfully\u001b[39m\u001b[22m`);
143+
}
144+
});
92145
});

test/colors/multiple-configs.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = [
2+
{
3+
name: 'first-config',
4+
entry: './src/first.js',
5+
stats: 'normal',
6+
},
7+
{
8+
name: 'second-config',
9+
entry: './src/second.js',
10+
stats: 'normal',
11+
},
12+
];

test/colors/src/first.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('first');

test/colors/src/second.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('second');

test/config/type/function-with-argv/function-with-argv.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ describe('function configuration', () => {
99
expect(stderr).toBeFalsy();
1010
expect(stdout).toBeTruthy();
1111
expect(exitCode).toBe(0);
12-
expect(stdout).toContain("argv: { color: true, mode: 'development' }");
12+
expect(stdout).toContain("argv: { mode: 'development' }");
1313
// Should generate the appropriate files
1414
expect(existsSync(resolve(__dirname, './dist/dev.js'))).toBeTruthy();
1515
});

test/json/json.test.js

+45-4
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@ const { run } = require('../utils/test-utils');
33
const { stat, readFile } = require('fs');
44
const { resolve } = require('path');
55

6+
const successMessage = 'stats are successfully stored as json to stats.json';
7+
68
describe('json flag', () => {
79
it('should return valid json', () => {
810
const { stdout, exitCode } = run(__dirname, ['--json']);
9-
1011
expect(() => JSON.parse(stdout)).not.toThrow();
1112
expect(exitCode).toBe(0);
12-
1313
expect(JSON.parse(stdout)['hash']).toBeDefined();
1414
});
1515

1616
it('should store json to a file', (done) => {
1717
const { stdout, exitCode } = run(__dirname, ['--json', 'stats.json']);
1818

19-
expect(stdout).toContain('stats are successfully stored as json to stats.json');
19+
expect(stdout).toContain(successMessage);
2020
expect(exitCode).toBe(0);
2121

2222
stat(resolve(__dirname, './stats.json'), (err, stats) => {
@@ -34,11 +34,52 @@ describe('json flag', () => {
3434
});
3535
});
3636

37+
it('should store json to a file and respect --color flag', (done) => {
38+
const { stdout, exitCode } = run(__dirname, ['--json', 'stats.json', '--color']);
39+
40+
expect(stdout).toContain(`[webpack-cli] \u001b[32m${successMessage}`);
41+
expect(exitCode).toBe(0);
42+
43+
stat(resolve(__dirname, './stats.json'), (err, stats) => {
44+
expect(err).toBe(null);
45+
expect(stats.isFile()).toBe(true);
46+
47+
readFile(resolve(__dirname, 'stats.json'), 'utf-8', (err, data) => {
48+
expect(err).toBe(null);
49+
expect(JSON.parse(data)['hash']).toBeTruthy();
50+
expect(JSON.parse(data)['version']).toBeTruthy();
51+
expect(JSON.parse(data)['time']).toBeTruthy();
52+
expect(() => JSON.parse(data)).not.toThrow();
53+
done();
54+
});
55+
});
56+
});
57+
58+
it('should store json to a file and respect --no-color', (done) => {
59+
const { stdout, exitCode } = run(__dirname, ['--json', 'stats.json', '--no-color']);
60+
61+
expect(stdout).not.toContain(`[webpack-cli] \u001b[32m${successMessage}`);
62+
expect(stdout).toContain(`[webpack-cli] ${successMessage}`);
63+
expect(exitCode).toBe(0);
64+
65+
stat(resolve(__dirname, './stats.json'), (err, stats) => {
66+
expect(err).toBe(null);
67+
expect(stats.isFile()).toBe(true);
68+
readFile(resolve(__dirname, 'stats.json'), 'utf-8', (err, data) => {
69+
expect(err).toBe(null);
70+
expect(JSON.parse(data)['hash']).toBeTruthy();
71+
expect(JSON.parse(data)['version']).toBeTruthy();
72+
expect(JSON.parse(data)['time']).toBeTruthy();
73+
expect(() => JSON.parse(data)).not.toThrow();
74+
done();
75+
});
76+
});
77+
});
78+
3779
it('should return valid json with -j alias', () => {
3880
const { stdout, exitCode } = run(__dirname, ['-j']);
3981
expect(() => JSON.parse(stdout)).not.toThrow();
4082
expect(exitCode).toBe(0);
41-
4283
expect(JSON.parse(stdout)['hash']).toBeDefined();
4384
});
4485
});

test/unknown/unknown.test.js

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
11
const { run } = require('../utils/test-utils');
22

3+
const unknownError = 'Unknown argument: --unknown';
4+
35
describe('unknown behaviour', () => {
4-
it('warns the user if an unknown flag is passed in', () => {
6+
it('throws error if an unknown flag is passed in', () => {
57
const { stderr, exitCode } = run(__dirname, ['--unknown']);
68
expect(stderr).toBeTruthy();
79
expect(stderr).toContain('Unknown argument: --unknown');
10+
expect(stderr).toContain(unknownError);
11+
expect(exitCode).toBe(2);
12+
});
13+
14+
it('should throw error and respect --color flag', () => {
15+
const { stderr, exitCode } = run(__dirname, ['--unknown', '--color']);
16+
expect(stderr).toBeTruthy();
17+
expect(stderr).toContain(`[webpack-cli] \u001b[31m${unknownError}`);
818
expect(exitCode).toBe(2);
919
});
20+
21+
it('throws error for unknow flag and respect --no-color', () => {
22+
const { stderr, exitCode } = run(__dirname, ['--unknown', '--no-color']);
23+
expect(stderr).toBeTruthy();
24+
expect(stderr).not.toContain(`[webpack-cli] \u001b[31m${unknownError}`);
25+
expect(stderr).toContain(unknownError);
26+
expect(exitCode).toBe(2);
27+
});
28+
1029
it('suggests the closest match to an unknown flag', () => {
1130
const { stderr, stdout, exitCode } = run(__dirname, ['--entyr', './a.js']);
1231
expect(stderr).toContain('Unknown argument: --entyr');

0 commit comments

Comments
 (0)