webpack-bundle-analyzer 5.2.0 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -29
- package/lib/BundleAnalyzerPlugin.js +125 -37
- package/lib/Logger.js +70 -12
- package/lib/analyzer.js +248 -121
- package/lib/bin/analyzer.js +72 -51
- package/lib/index.js +2 -2
- package/lib/parseUtils.js +271 -162
- package/lib/sizeUtils.js +24 -10
- package/lib/statsUtils.js +38 -16
- package/lib/template.js +83 -36
- package/lib/tree/BaseFolder.js +84 -23
- package/lib/tree/ConcatenatedModule.js +78 -20
- package/lib/tree/ContentFolder.js +36 -7
- package/lib/tree/ContentModule.js +38 -9
- package/lib/tree/Folder.js +51 -15
- package/lib/tree/Module.js +67 -14
- package/lib/tree/Node.js +10 -3
- package/lib/tree/utils.js +14 -4
- package/lib/utils.js +52 -24
- package/lib/viewer.js +182 -78
- package/package.json +85 -76
- package/public/viewer.js +59 -8
- package/public/viewer.js.LICENSE.txt +20 -7
- package/public/viewer.js.map +1 -1
package/lib/tree/Folder.js
CHANGED
|
@@ -4,44 +4,77 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
var
|
|
8
|
-
var _BaseFolder = _interopRequireDefault(require("./BaseFolder"));
|
|
9
|
-
var _ConcatenatedModule = _interopRequireDefault(require("./ConcatenatedModule"));
|
|
10
|
-
var
|
|
11
|
-
var
|
|
7
|
+
var _sizeUtils = require("../sizeUtils.js");
|
|
8
|
+
var _BaseFolder = _interopRequireDefault(require("./BaseFolder.js"));
|
|
9
|
+
var _ConcatenatedModule = _interopRequireDefault(require("./ConcatenatedModule.js"));
|
|
10
|
+
var _Module = _interopRequireDefault(require("./Module.js"));
|
|
11
|
+
var _utils = require("./utils.js");
|
|
12
12
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
/** @typedef {import("webpack").StatsModule} StatsModule */
|
|
14
|
+
/** @typedef {import("../analyzer").AnalyzerOptions} AnalyzerOptions */
|
|
15
|
+
/** @typedef {import("../analyzer").CompressionAlgorithm} CompressionAlgorithm */
|
|
16
|
+
/** @typedef {import("./Module").SizeFields} SizeFields */
|
|
17
|
+
/** @typedef {import("./BaseFolder").BaseFolderChartData} BaseFolderChartData */
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {object} OwnFolderChartData
|
|
21
|
+
* @property {number} parsedSize parsed size
|
|
22
|
+
* @property {number | undefined} gzipSize gzip size
|
|
23
|
+
* @property {number | undefined} brotliSize brotli size
|
|
24
|
+
* @property {number | undefined} zstdSize zstd size
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** @typedef {BaseFolderChartData & OwnFolderChartData} FolderChartData */
|
|
28
|
+
|
|
13
29
|
class Folder extends _BaseFolder.default {
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} name name
|
|
32
|
+
* @param {AnalyzerOptions} opts options
|
|
33
|
+
*/
|
|
14
34
|
constructor(name, opts) {
|
|
15
35
|
super(name);
|
|
36
|
+
/** @type {AnalyzerOptions} */
|
|
16
37
|
this.opts = opts;
|
|
17
38
|
}
|
|
18
39
|
get parsedSize() {
|
|
19
40
|
return this.src ? this.src.length : 0;
|
|
20
41
|
}
|
|
21
42
|
get gzipSize() {
|
|
22
|
-
return this.opts.compressionAlgorithm ===
|
|
43
|
+
return this.opts.compressionAlgorithm === "gzip" ? this.getCompressedSize("gzip") : undefined;
|
|
23
44
|
}
|
|
24
45
|
get brotliSize() {
|
|
25
|
-
return this.opts.compressionAlgorithm ===
|
|
46
|
+
return this.opts.compressionAlgorithm === "brotli" ? this.getCompressedSize("brotli") : undefined;
|
|
26
47
|
}
|
|
27
48
|
get zstdSize() {
|
|
28
|
-
return this.opts.compressionAlgorithm ===
|
|
49
|
+
return this.opts.compressionAlgorithm === "zstd" ? this.getCompressedSize("zstd") : undefined;
|
|
29
50
|
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param {CompressionAlgorithm} compressionAlgorithm compression algorithm
|
|
54
|
+
* @returns {number | undefined} compressed size
|
|
55
|
+
*/
|
|
30
56
|
getCompressedSize(compressionAlgorithm) {
|
|
31
|
-
const key = `_${
|
|
32
|
-
|
|
57
|
+
const key = /** @type {`_${CompressionAlgorithm}Size`} */
|
|
58
|
+
`_${compressionAlgorithm}Size`;
|
|
59
|
+
if (!Object.hasOwn(this, key)) {
|
|
60
|
+
/** @type {Folder & SizeFields} */
|
|
33
61
|
this[key] = this.src ? (0, _sizeUtils.getCompressedSize)(compressionAlgorithm, this.src) : 0;
|
|
34
62
|
}
|
|
35
|
-
return this[key];
|
|
63
|
+
return /** @type {Folder & SizeFields} */this[key];
|
|
36
64
|
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {StatsModule} moduleData stats module
|
|
68
|
+
*/
|
|
37
69
|
addModule(moduleData) {
|
|
38
70
|
const pathParts = (0, _utils.getModulePathParts)(moduleData);
|
|
39
71
|
if (!pathParts) {
|
|
40
72
|
return;
|
|
41
73
|
}
|
|
42
74
|
const [folders, fileName] = [pathParts.slice(0, -1), pathParts[pathParts.length - 1]];
|
|
75
|
+
/** @type {BaseFolder} */
|
|
43
76
|
let currentFolder = this;
|
|
44
|
-
|
|
77
|
+
for (const folderName of folders) {
|
|
45
78
|
let childNode = currentFolder.getChild(folderName);
|
|
46
79
|
if (
|
|
47
80
|
// Folder is not created yet
|
|
@@ -54,11 +87,15 @@ class Folder extends _BaseFolder.default {
|
|
|
54
87
|
childNode = currentFolder.addChildFolder(new Folder(folderName, this.opts));
|
|
55
88
|
}
|
|
56
89
|
currentFolder = childNode;
|
|
57
|
-
}
|
|
90
|
+
}
|
|
58
91
|
const ModuleConstructor = moduleData.modules ? _ConcatenatedModule.default : _Module.default;
|
|
59
92
|
const module = new ModuleConstructor(fileName, moduleData, this, this.opts);
|
|
60
93
|
currentFolder.addChildModule(module);
|
|
61
94
|
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @returns {FolderChartData} chart data
|
|
98
|
+
*/
|
|
62
99
|
toChartData() {
|
|
63
100
|
return {
|
|
64
101
|
...super.toChartData(),
|
|
@@ -69,5 +106,4 @@ class Folder extends _BaseFolder.default {
|
|
|
69
106
|
};
|
|
70
107
|
}
|
|
71
108
|
}
|
|
72
|
-
exports.default = Folder;
|
|
73
|
-
;
|
|
109
|
+
exports.default = Folder;
|
package/lib/tree/Module.js
CHANGED
|
@@ -4,13 +4,47 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
var
|
|
8
|
-
var
|
|
7
|
+
var _sizeUtils = require("../sizeUtils.js");
|
|
8
|
+
var _Node = _interopRequireDefault(require("./Node.js"));
|
|
9
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
/** @typedef {import("webpack").StatsModule} StatsModule */
|
|
11
|
+
/** @typedef {import("../sizeUtils").Algorithm} CompressionAlgorithm */
|
|
12
|
+
|
|
13
|
+
/** @typedef {{ compressionAlgorithm: CompressionAlgorithm }} ModuleOptions */
|
|
14
|
+
|
|
15
|
+
/** @typedef {"parsedSize" | "gzipSize" | "brotliSize" | "zstdSize"} SizeType */
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {object} ModuleChartData
|
|
19
|
+
* @property {string | number | undefined} id id
|
|
20
|
+
* @property {string} label label
|
|
21
|
+
* @property {string} path path
|
|
22
|
+
* @property {number | undefined} statSize stat size
|
|
23
|
+
* @property {number | undefined} parsedSize parsed size
|
|
24
|
+
* @property {number | undefined} gzipSize gzip size
|
|
25
|
+
* @property {number | undefined} brotliSize brotli size
|
|
26
|
+
* @property {number | undefined} zstdSize zstd size
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @typedef {object} SizeFields
|
|
31
|
+
* @property {number=} _gzipSize gzip size
|
|
32
|
+
* @property {number=} _brotliSize brotli size
|
|
33
|
+
* @property {number=} _zstdSize zstd size
|
|
34
|
+
*/
|
|
35
|
+
|
|
10
36
|
class Module extends _Node.default {
|
|
37
|
+
/**
|
|
38
|
+
* @param {string} name name
|
|
39
|
+
* @param {StatsModule} data data
|
|
40
|
+
* @param {Node | undefined} parent parent
|
|
41
|
+
* @param {ModuleOptions} opts options
|
|
42
|
+
*/
|
|
11
43
|
constructor(name, data, parent, opts) {
|
|
12
44
|
super(name, parent);
|
|
45
|
+
/** @type {StatsModule} */
|
|
13
46
|
this.data = data;
|
|
47
|
+
/** @type {ModuleOptions} */
|
|
14
48
|
this.opts = opts;
|
|
15
49
|
}
|
|
16
50
|
get src() {
|
|
@@ -18,12 +52,16 @@ class Module extends _Node.default {
|
|
|
18
52
|
}
|
|
19
53
|
set src(value) {
|
|
20
54
|
this.data.parsedSrc = value;
|
|
21
|
-
delete this._gzipSize;
|
|
22
|
-
delete this._brotliSize;
|
|
23
|
-
delete this._zstdSize;
|
|
55
|
+
delete (/** @type {Module & SizeFields} */this._gzipSize);
|
|
56
|
+
delete (/** @type {Module & SizeFields} */this._brotliSize);
|
|
57
|
+
delete (/** @type {Module & SizeFields} */this._zstdSize);
|
|
24
58
|
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @returns {number} size
|
|
62
|
+
*/
|
|
25
63
|
get size() {
|
|
26
|
-
return this.data.size;
|
|
64
|
+
return /** @type {number} */this.data.size;
|
|
27
65
|
}
|
|
28
66
|
set size(value) {
|
|
29
67
|
this.data.size = value;
|
|
@@ -44,29 +82,45 @@ class Module extends _Node.default {
|
|
|
44
82
|
return this.src ? this.src.length : undefined;
|
|
45
83
|
}
|
|
46
84
|
getGzipSize() {
|
|
47
|
-
return this.opts.compressionAlgorithm ===
|
|
85
|
+
return this.opts.compressionAlgorithm === "gzip" ? this.getCompressedSize("gzip") : undefined;
|
|
48
86
|
}
|
|
49
87
|
getBrotliSize() {
|
|
50
|
-
return this.opts.compressionAlgorithm ===
|
|
88
|
+
return this.opts.compressionAlgorithm === "brotli" ? this.getCompressedSize("brotli") : undefined;
|
|
51
89
|
}
|
|
52
90
|
getZstdSize() {
|
|
53
|
-
return this.opts.compressionAlgorithm ===
|
|
91
|
+
return this.opts.compressionAlgorithm === "zstd" ? this.getCompressedSize("zstd") : undefined;
|
|
54
92
|
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {CompressionAlgorithm} compressionAlgorithm compression algorithm
|
|
96
|
+
* @returns {number | undefined} compressed size
|
|
97
|
+
*/
|
|
55
98
|
getCompressedSize(compressionAlgorithm) {
|
|
56
|
-
const key = `_${
|
|
99
|
+
const key = /** @type {`_${CompressionAlgorithm}Size`} */
|
|
100
|
+
`_${compressionAlgorithm}Size`;
|
|
57
101
|
if (!(key in this)) {
|
|
102
|
+
/** @type {Module & SizeFields} */
|
|
58
103
|
this[key] = this.src ? (0, _sizeUtils.getCompressedSize)(compressionAlgorithm, this.src) : undefined;
|
|
59
104
|
}
|
|
60
|
-
return this[key];
|
|
105
|
+
return /** @type {Module & SizeFields} */this[key];
|
|
61
106
|
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @param {StatsModule} data data
|
|
110
|
+
*/
|
|
62
111
|
mergeData(data) {
|
|
63
112
|
if (data.size) {
|
|
113
|
+
/** @type {number} */
|
|
64
114
|
this.size += data.size;
|
|
65
115
|
}
|
|
66
116
|
if (data.parsedSrc) {
|
|
67
|
-
this.src = (this.src ||
|
|
117
|
+
this.src = (this.src || "") + data.parsedSrc;
|
|
68
118
|
}
|
|
69
119
|
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @returns {ModuleChartData} module chart data
|
|
123
|
+
*/
|
|
70
124
|
toChartData() {
|
|
71
125
|
return {
|
|
72
126
|
id: this.data.id,
|
|
@@ -80,5 +134,4 @@ class Module extends _Node.default {
|
|
|
80
134
|
};
|
|
81
135
|
}
|
|
82
136
|
}
|
|
83
|
-
exports.default = Module;
|
|
84
|
-
;
|
|
137
|
+
exports.default = Module;
|
package/lib/tree/Node.js
CHANGED
|
@@ -5,22 +5,29 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
class Node {
|
|
8
|
+
/**
|
|
9
|
+
* @param {string} name name
|
|
10
|
+
* @param {Node=} parent parent
|
|
11
|
+
*/
|
|
8
12
|
constructor(name, parent) {
|
|
13
|
+
/** @type {string} */
|
|
9
14
|
this.name = name;
|
|
15
|
+
/** @type {Node | undefined} */
|
|
10
16
|
this.parent = parent;
|
|
11
17
|
}
|
|
12
18
|
get path() {
|
|
19
|
+
/** @type {string[]} */
|
|
13
20
|
const path = [];
|
|
21
|
+
/** @type {Node | undefined} */
|
|
14
22
|
let node = this;
|
|
15
23
|
while (node) {
|
|
16
24
|
path.push(node.name);
|
|
17
25
|
node = node.parent;
|
|
18
26
|
}
|
|
19
|
-
return path.reverse().join(
|
|
27
|
+
return path.reverse().join("/");
|
|
20
28
|
}
|
|
21
29
|
get isRoot() {
|
|
22
30
|
return !this.parent;
|
|
23
31
|
}
|
|
24
32
|
}
|
|
25
|
-
exports.default = Node;
|
|
26
|
-
;
|
|
33
|
+
exports.default = Node;
|
package/lib/tree/utils.js
CHANGED
|
@@ -5,18 +5,28 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.getModulePathParts = getModulePathParts;
|
|
7
7
|
const MULTI_MODULE_REGEXP = /^multi /u;
|
|
8
|
+
|
|
9
|
+
/** @typedef {import("webpack").StatsModule} StatsModule */
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {StatsModule} moduleData moduleData
|
|
13
|
+
* @returns {string[] | null} module path parts
|
|
14
|
+
*/
|
|
8
15
|
function getModulePathParts(moduleData) {
|
|
9
|
-
if (MULTI_MODULE_REGEXP.test(moduleData.identifier)) {
|
|
16
|
+
if (moduleData.identifier && MULTI_MODULE_REGEXP.test(moduleData.identifier)) {
|
|
10
17
|
return [moduleData.identifier];
|
|
11
18
|
}
|
|
12
|
-
|
|
19
|
+
if (!moduleData.name) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const loaders = moduleData.name.split("!");
|
|
13
23
|
// Removing loaders from module path: they're joined by `!` and the last part is a raw module path
|
|
14
24
|
const parsedPath = loaders[loaders.length - 1]
|
|
15
25
|
// Splitting module path into parts
|
|
16
|
-
.split(
|
|
26
|
+
.split("/")
|
|
17
27
|
// Removing first `.`
|
|
18
28
|
.slice(1)
|
|
19
29
|
// Replacing `~` with `node_modules`
|
|
20
|
-
.map(part => part ===
|
|
30
|
+
.map(part => part === "~" ? "node_modules" : part);
|
|
21
31
|
return parsedPath.length ? parsedPath : null;
|
|
22
32
|
}
|
package/lib/utils.js
CHANGED
|
@@ -1,21 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
/** @typedef {import("net").AddressInfo} AddressInfo */
|
|
4
|
+
/** @typedef {import("webpack").StatsAsset} StatsAsset */
|
|
5
|
+
|
|
3
6
|
const {
|
|
4
7
|
inspect,
|
|
5
8
|
types
|
|
6
|
-
} = require(
|
|
7
|
-
const opener = require(
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
} = require("node:util");
|
|
10
|
+
const opener = require("opener");
|
|
11
|
+
|
|
12
|
+
/** @typedef {import("./BundleAnalyzerPlugin").ExcludeAssets} ExcludeAssets */
|
|
13
|
+
/** @typedef {import("./BundleAnalyzerPlugin").AnalyzerUrl} AnalyzerUrl */
|
|
14
|
+
/** @typedef {import("./Logger")} Logger */
|
|
15
|
+
|
|
16
|
+
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {ExcludeAssets} excludePatterns exclude patterns
|
|
20
|
+
* @returns {(asset: string) => boolean} function to filter
|
|
21
|
+
*/
|
|
10
22
|
function createAssetsFilter(excludePatterns) {
|
|
23
|
+
/** @type {((asset: string) => void | boolean)[]} */
|
|
11
24
|
const excludeFunctions = (Array.isArray(excludePatterns) ? excludePatterns : [excludePatterns]).filter(Boolean).map(pattern => {
|
|
12
|
-
if (typeof pattern ===
|
|
13
|
-
pattern = new RegExp(pattern,
|
|
25
|
+
if (typeof pattern === "string") {
|
|
26
|
+
pattern = new RegExp(pattern, "u");
|
|
14
27
|
}
|
|
15
28
|
if (types.isRegExp(pattern)) {
|
|
16
|
-
return
|
|
29
|
+
return (
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} asset asset
|
|
32
|
+
* @returns {boolean} true when need to exclude, otherwise false
|
|
33
|
+
*/
|
|
34
|
+
asset => pattern.test(asset)
|
|
35
|
+
);
|
|
17
36
|
}
|
|
18
|
-
if (typeof pattern !==
|
|
37
|
+
if (typeof pattern !== "function") {
|
|
19
38
|
throw new TypeError(`Pattern should be either string, RegExp or a function, but "${inspect(pattern, {
|
|
20
39
|
depth: 0
|
|
21
40
|
})}" got.`);
|
|
@@ -24,16 +43,24 @@ function createAssetsFilter(excludePatterns) {
|
|
|
24
43
|
});
|
|
25
44
|
if (excludeFunctions.length) {
|
|
26
45
|
return asset => excludeFunctions.every(fn => fn(asset) !== true);
|
|
27
|
-
} else {
|
|
28
|
-
return () => true;
|
|
29
46
|
}
|
|
47
|
+
return () => true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** @type {AnalyzerUrl} */
|
|
51
|
+
function defaultAnalyzerUrl(options) {
|
|
52
|
+
const {
|
|
53
|
+
listenHost,
|
|
54
|
+
boundAddress
|
|
55
|
+
} = options;
|
|
56
|
+
return `http://${listenHost}:${ /** @type {AddressInfo} */boundAddress.port}`;
|
|
30
57
|
}
|
|
31
58
|
|
|
32
59
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
|
|
36
|
-
|
|
60
|
+
* get string of current time, format: dd/MMM HH:mm
|
|
61
|
+
* @returns {string} default title
|
|
62
|
+
*/
|
|
63
|
+
function defaultTitle() {
|
|
37
64
|
const time = new Date();
|
|
38
65
|
const year = time.getFullYear();
|
|
39
66
|
const month = MONTHS[time.getMonth()];
|
|
@@ -41,23 +68,24 @@ exports.defaultTitle = function () {
|
|
|
41
68
|
const hour = `0${time.getHours()}`.slice(-2);
|
|
42
69
|
const minute = `0${time.getMinutes()}`.slice(-2);
|
|
43
70
|
const currentTime = `${day} ${month} ${year} at ${hour}:${minute}`;
|
|
44
|
-
return `${process.env.npm_package_name ||
|
|
45
|
-
}
|
|
46
|
-
exports.defaultAnalyzerUrl = function (options) {
|
|
47
|
-
const {
|
|
48
|
-
listenHost,
|
|
49
|
-
boundAddress
|
|
50
|
-
} = options;
|
|
51
|
-
return `http://${listenHost}:${boundAddress.port}`;
|
|
52
|
-
};
|
|
71
|
+
return `${process.env.npm_package_name || "Webpack Bundle Analyzer"} [${currentTime}]`;
|
|
72
|
+
}
|
|
53
73
|
|
|
54
74
|
/**
|
|
55
75
|
* Calls opener on a URI, but silently try / catches it.
|
|
76
|
+
* @param {string} uri URI
|
|
77
|
+
* @param {Logger} logger logger
|
|
56
78
|
*/
|
|
57
|
-
|
|
79
|
+
function open(uri, logger) {
|
|
58
80
|
try {
|
|
59
81
|
opener(uri);
|
|
60
82
|
} catch (err) {
|
|
61
83
|
logger.debug(`Opener failed to open "${uri}":\n${err}`);
|
|
62
84
|
}
|
|
85
|
+
}
|
|
86
|
+
module.exports = {
|
|
87
|
+
createAssetsFilter,
|
|
88
|
+
defaultAnalyzerUrl,
|
|
89
|
+
defaultTitle,
|
|
90
|
+
open
|
|
63
91
|
};
|