Skip to content

Commit 3907517

Browse files
authored
feat: allow users to store stats as json to a file (#1835)
1 parent 6f49e96 commit 3907517

6 files changed

Lines changed: 64 additions & 27 deletions

File tree

packages/webpack-cli/README.md

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,28 +36,28 @@ yarn add webpack-cli --dev
3636
### webpack 4
3737

3838
```
39-
--entry string[] The entry point(s) of your application.
40-
-c, --config string[] Provide path to webpack configuration file(s)
41-
--config-name string[] Name of the configuration to use
42-
-m, --merge Merge several configurations using webpack-merge
43-
--progress Print compilation progress during build
44-
--color Enables colors on console
45-
--no-color Disable colors on console
46-
--env string Environment passed to the configuration when it is a function
47-
--name string Name of the configuration. Used when loading multiple configurations
48-
--help Outputs list of supported flags
49-
-o, --output string Output location of the file generated by webpack
50-
-t, --target string Sets the build target
51-
-w, --watch Watch for files changes
52-
-h, --hot Enables Hot Module Replacement
53-
--no-hot Disables Hot Module Replacement
54-
-d, --devtool string Controls if and how source maps are generated.
55-
--prefetch string Prefetch this request
56-
-j, --json Prints result as JSON
57-
--mode string Defines the mode to pass to webpack
58-
-v, --version Get current version
59-
--stats string It instructs webpack on how to treat the stats
60-
--no-stats Disables stats output
39+
--entry string[] The entry point(s) of your application.
40+
-c, --config string[] Provide path to webpack configuration file(s)
41+
--config-name string[] Name of the configuration to use
42+
-m, --merge Merge several configurations using webpack-merge
43+
--progress Print compilation progress during build
44+
--color Enables colors on console
45+
--no-color Disable colors on console
46+
--env string Environment passed to the configuration when it is a function
47+
--name string Name of the configuration. Used when loading multiple configurations
48+
--help Outputs list of supported flags
49+
-o, --output string Output location of the file generated by webpack
50+
-t, --target string Sets the build target
51+
-w, --watch Watch for files changes
52+
-h, --hot Enables Hot Module Replacement
53+
--no-hot Disables Hot Module Replacement
54+
-d, --devtool string Controls if and how source maps are generated.
55+
--prefetch string Prefetch this request
56+
-j, --json string, boolean Prints result as JSON or store it in a file
57+
--mode string Defines the mode to pass to webpack
58+
-v, --version Get current version
59+
--stats string, boolean It instructs webpack on how to treat the stats
60+
--no-stats Disables stats output
6161
```
6262

6363
### webpack 5

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const resolveStats = (args) => {
1414
finalOptions.options.stats = stats;
1515
}
1616
if (json) {
17-
finalOptions.outputOptions.json = true;
17+
finalOptions.outputOptions.json = json;
1818
}
1919
return finalOptions;
2020
};

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const { packageExists } = require('@webpack-cli/package-utils');
22
const webpack = packageExists('webpack') ? require('webpack') : undefined;
33
const logger = require('./logger');
4+
const { writeFileSync } = require('fs');
45
const bailAndWatchWarning = require('./warnings/bailAndWatchWarning');
56
const { CompilerOutput } = require('./CompilerOutput');
67

@@ -58,7 +59,7 @@ class Compiler {
5859
if (!outputOptions.watch && (stats.hasErrors() || stats.hasWarnings())) {
5960
process.exitCode = 1;
6061
}
61-
if (outputOptions.json) {
62+
if (outputOptions.json === true) {
6263
process.stdout.write(JSON.stringify(stats.toJson(outputOptions), null, 2) + '\n');
6364
} else if (stats.hash !== lastHash) {
6465
lastHash = stats.hash;
@@ -69,6 +70,15 @@ class Compiler {
6970
statsErrors.push({ name: statErr.message, loc: errLoc });
7071
});
7172
}
73+
const JSONStats = JSON.stringify(stats.toJson(outputOptions), null, 2);
74+
if (typeof outputOptions.json === 'string') {
75+
try {
76+
writeFileSync(outputOptions.json, JSONStats);
77+
logger.info(`stats are successfully stored as json to ${outputOptions.json}`);
78+
} catch (err) {
79+
logger.error(err);
80+
}
81+
}
7282
return this.generateOutput(outputOptions, stats, statsErrors);
7383
}
7484
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,9 @@ const core = [
174174
{
175175
name: 'json',
176176
usage: '--json',
177-
type: Boolean,
177+
type: [String, Boolean],
178178
alias: 'j',
179-
description: 'Prints result as JSON',
179+
description: 'Prints result as JSON or store it in a file',
180180
},
181181
{
182182
name: 'mode',

scripts/cleanupTest.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const rimraf = require('rimraf');
33
const { join } = require('path');
44
const collectTestFolders = require('./utils');
55

6-
const outputDirectories = ['bin', 'binary', 'dist', 'test', 'test-assets', 'test-plugin', 'test-loader'];
6+
const outputDirectories = ['bin', 'binary', 'dist', 'test', 'test-assets', 'test-plugin', 'test-loader', 'stats.json'];
77

88
function folderStrategy(stats, file) {
99
return stats.isDirectory() && outputDirectories.includes(file);

test/json/json.test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22
const { run } = require('../utils/test-utils');
3+
const { stat, readFile } = require('fs');
4+
const { resolve } = require('path');
35

46
describe('json flag', () => {
57
it('should return valid json', () => {
@@ -10,9 +12,31 @@ describe('json flag', () => {
1012
return JSON.parse(stdout);
1113
};
1214
// check the JSON is valid.
15+
expect(JSON.parse(stdout)['hash']).toBeTruthy();
16+
expect(JSON.parse(stdout)['version']).toBeTruthy();
17+
expect(JSON.parse(stdout)['time']).toBeTruthy();
1318
expect(parseJson).not.toThrow();
1419
});
1520

21+
it('should store json to a file', (done) => {
22+
const { stdout } = run(__dirname, ['--json', 'stats.json']);
23+
24+
expect(stdout).toContain('stats are successfully stored as json to stats.json');
25+
stat(resolve(__dirname, './stats.json'), (err, stats) => {
26+
expect(err).toBe(null);
27+
expect(stats.isFile()).toBe(true);
28+
done();
29+
});
30+
readFile(resolve(__dirname, 'stats.json'), 'utf-8', (err, data) => {
31+
expect(err).toBe(null);
32+
expect(JSON.parse(data)['hash']).toBeTruthy();
33+
expect(JSON.parse(data)['version']).toBeTruthy();
34+
expect(JSON.parse(data)['time']).toBeTruthy();
35+
expect(() => JSON.parse(data)).not.toThrow();
36+
done();
37+
});
38+
});
39+
1640
it('should return valid json with -j alias', () => {
1741
const { stdout } = run(__dirname, ['-j']);
1842

@@ -21,6 +45,9 @@ describe('json flag', () => {
2145
return JSON.parse(stdout);
2246
};
2347
// check the JSON is valid.
48+
expect(JSON.parse(stdout)['hash']).toBeTruthy();
49+
expect(JSON.parse(stdout)['version']).toBeTruthy();
50+
expect(JSON.parse(stdout)['time']).toBeTruthy();
2451
expect(parseJson).not.toThrow();
2552
});
2653
});

0 commit comments

Comments
 (0)