1 | ;
|
2 |
|
3 | const INDENT = 2;
|
4 | const DEFAULT_TRANSFORM = (data) => JSON.stringify(data, null, INDENT);
|
5 |
|
6 | /**
|
7 | * Stats writer module.
|
8 | *
|
9 | * Stats can be a string or array (we'll have array due to source maps):
|
10 | *
|
11 | * ```js
|
12 | * "assetsByChunkName": {
|
13 | * "main": [
|
14 | * "cd6371d4131fbfbefaa7.bundle.js",
|
15 | * "../js-map/cd6371d4131fbfbefaa7.bundle.js.map"
|
16 | * ]
|
17 | * },
|
18 | * ```
|
19 | *
|
20 | * **Note**: The stats object is **big**. It includes the entire source included
|
21 | * in a bundle. Thus, we default `opts.fields` to `["assetsByChunkName"]` to
|
22 | * only include those. However, if you want the _whole thing_ (maybe doing an
|
23 | * `opts.transform` function), then you can set `fields: null` in options to
|
24 | * get **all** of the stats object.
|
25 | *
|
26 | * You may also pass a custom stats config object (or string preset) via `opts.stats`
|
27 | * in order to select exactly what you want added to the data passed to the transform.
|
28 | * When `opts.stats` is passed, `opts.fields` will default to `null`.
|
29 | *
|
30 | * See:
|
31 | * - https://webpack.js.org/configuration/stats/#stats
|
32 | * - https://webpack.js.org/api/node/#stats-object
|
33 | *
|
34 | * **`filename`**: The `opts.filename` option can be a file name or path relative to
|
35 | * `output.path` in webpack configuration. It should not be absolute.
|
36 | *
|
37 | * **`transform`**: By default, the retrieved stats object is `JSON.stringify`'ed
|
38 | * but by supplying an alternate transform you can target _any_ output format.
|
39 | * See [`test/webpack4/webpack.config.js`](test/webpack4/webpack.config.js) for
|
40 | * various examples including Markdown output.
|
41 | *
|
42 | * - **Warning**: The output of `transform` should be a `String`, not an object.
|
43 | * On Node `v4.x` if you return a real object in `transform`, then webpack
|
44 | * will break with a `TypeError` (See #8). Just adding a simple
|
45 | * `JSON.stringify()` around your object is usually what you need to solve
|
46 | * any problems.
|
47 | *
|
48 | * @param {Object} opts options
|
49 | * @param {String} opts.filename output file name (Default: `"stats.json`")
|
50 | * @param {Array} opts.fields fields of stats obj to keep (Default: `["assetsByChunkName"]`)
|
51 | * @param {Object|String} opts.stats stats config object or string preset (Default: `{}`)
|
52 | * @param {Function|Promise} opts.transform transform stats obj (Default: `JSON.stringify()`)
|
53 | *
|
54 | * @api public
|
55 | */
|
56 | class StatsWriterPlugin {
|
57 | constructor(opts) {
|
58 | opts = opts || {};
|
59 | this.opts = {};
|
60 | this.opts.filename = opts.filename || "stats.json";
|
61 | this.opts.fields = typeof opts.fields !== "undefined" ? opts.fields : ["assetsByChunkName"];
|
62 | this.opts.stats = opts.stats || {};
|
63 | this.opts.transform = opts.transform || DEFAULT_TRANSFORM;
|
64 |
|
65 | if (typeof opts.stats !== "undefined" && typeof opts.fields === "undefined") {
|
66 | // if custom stats config provided, do not filter fields unless explicitly configured
|
67 | this.opts.fields = null;
|
68 | }
|
69 | }
|
70 |
|
71 | apply(compiler) {
|
72 | if (compiler.hooks) {
|
73 | compiler.hooks.emit.tapPromise("stats-writer-plugin", this.emitStats.bind(this));
|
74 | } else {
|
75 | compiler.plugin("emit", this.emitStats.bind(this));
|
76 | }
|
77 | }
|
78 |
|
79 | emitStats(curCompiler, callback) {
|
80 | // Get stats.
|
81 | // The second argument automatically skips heavy options (reasons, source, etc)
|
82 | // if they are otherwise unspecified.
|
83 | let stats = curCompiler.getStats().toJson(this.opts.stats, "forToString");
|
84 |
|
85 | // Filter to fields.
|
86 | if (this.opts.fields) {
|
87 | stats = this.opts.fields.reduce((memo, key) => {
|
88 | memo[key] = stats[key];
|
89 | return memo;
|
90 | }, {});
|
91 | }
|
92 |
|
93 | // Transform to string.
|
94 | let err;
|
95 | return Promise.resolve()
|
96 |
|
97 | // Transform.
|
98 | .then(() => this.opts.transform(stats, {
|
99 | compiler: curCompiler
|
100 | }))
|
101 | .catch((e) => { err = e; })
|
102 |
|
103 | // Finish up.
|
104 | .then((statsStr) => {
|
105 | // Handle errors.
|
106 | if (err) {
|
107 | curCompiler.errors.push(err);
|
108 | if (callback) { return void callback(err); }
|
109 | throw err;
|
110 | }
|
111 |
|
112 | // Add to assets.
|
113 | curCompiler.assets[this.opts.filename] = {
|
114 | source() {
|
115 | return statsStr;
|
116 | },
|
117 | size() {
|
118 | return statsStr.length;
|
119 | }
|
120 | };
|
121 |
|
122 | if (callback) { return void callback(); }
|
123 | });
|
124 | }
|
125 | }
|
126 |
|
127 | module.exports = StatsWriterPlugin;
|