webpack-bundle-analyzer 4.6.1 → 4.8.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/CHANGELOG.md CHANGED
@@ -12,6 +12,20 @@ _Note: Gaps between patch versions are faulty, broken or test releases._
12
12
 
13
13
  ## UNRELEASED
14
14
 
15
+ ## 4.8.0
16
+
17
+ * **Improvement**
18
+ * Support reading large (>500MB) stats.json files ([#423](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/423) by [@henry-alakazhang](https://github.com/henry-alakazhang))
19
+ * Improve search UX by graying out non-matches ([#554](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/554) by [@starpit](https://github.com/starpit))
20
+
21
+ * **Internal**
22
+ * Add Node.js v16.x to CI and update GitHub actions ([#539](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/539) by [@amareshsm](https://github.com/amareshsm))
23
+
24
+ ## 4.7.0
25
+
26
+ * **New Feature**
27
+ * Add the ability to filter to displaying only initial chunks per entrypoint ([#519](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/519) by [@pas-trop-de-zele](https://github.com/pas-trop-de-zele))
28
+
15
29
  ## 4.6.1
16
30
 
17
31
  * **Bug Fix**
package/README.md CHANGED
@@ -1,6 +1,5 @@
1
1
  [![npm][npm]][npm-url]
2
2
  [![node][node]][node-url]
3
- [![deps][deps]][deps-url]
4
3
  [![tests][tests]][tests-url]
5
4
  [![downloads][downloads]][downloads-url]
6
5
 
@@ -58,7 +57,7 @@ new BundleAnalyzerPlugin(options?: object)
58
57
  |:--:|:--:|:----------|
59
58
  |**`analyzerMode`**|One of: `server`, `static`, `json`, `disabled`|Default: `server`. In `server` mode analyzer will start HTTP server to show bundle report. In `static` mode single HTML file with bundle report will be generated. In `json` mode single JSON file with bundle report will be generated. In `disabled` mode you can use this plugin to just generate Webpack Stats JSON file by setting `generateStatsFile` to `true`. |
60
59
  |**`analyzerHost`**|`{String}`|Default: `127.0.0.1`. Host that will be used in `server` mode to start HTTP server.|
61
- |**`analyzerPort`**|`{Number}` or `auto`|Default: `8888`. Port that will be used in `server` mode to start HTTP server.|
60
+ |**`analyzerPort`**|`{Number}` or `auto`|Default: `8888`. Port that will be used in `server` mode to start HTTP server. If `analyzerPort` is `auto`, the operating system will assign an arbitrary unused port |
62
61
  |**`analyzerUrl`**|`{Function}` called with `{ listenHost: string, listenHost: string, boundAddress: server.address}`. [server.address comes from Node.js](https://nodejs.org/api/net.html#serveraddress)| Default: `http://${listenHost}:${boundAddress.port}`. The URL printed to console with server mode.|
63
62
  |**`reportFilename`**|`{String}`|Default: `report.html`. Path to bundle report file that will be generated in `static` mode. It can be either an absolute path or a path relative to a bundle output directory (which is output.path in webpack config).|
64
63
  |**`reportTitle`**|`{String\|function}`|Default: function that returns pretty printed current date and time. Content of the HTML `title` element; or a function of the form `() => string` that provides the content.|
@@ -211,9 +210,6 @@ To get more information about it you can read [issue #147](https://github.com/we
211
210
  [node]: https://img.shields.io/node/v/webpack-bundle-analyzer.svg
212
211
  [node-url]: https://nodejs.org
213
212
 
214
- [deps]: https://david-dm.org/webpack-contrib/webpack-bundle-analyzer.svg
215
- [deps-url]: https://david-dm.org/webpack-contrib/webpack-bundle-analyzer
216
-
217
213
  [tests]: http://img.shields.io/travis/webpack-contrib/webpack-bundle-analyzer.svg
218
214
  [tests-url]: https://travis-ci.org/webpack-contrib/webpack-bundle-analyzer
219
215
 
package/lib/analyzer.js CHANGED
@@ -8,6 +8,10 @@ const _ = require('lodash');
8
8
 
9
9
  const gzipSize = require('gzip-size');
10
10
 
11
+ const {
12
+ parseChunked
13
+ } = require('@discoveryjs/json-ext');
14
+
11
15
  const Logger = require('./Logger');
12
16
 
13
17
  const Folder = require('./tree/Folder').default;
@@ -155,22 +159,30 @@ function getViewerData(bundleStats, bundleDir, opts) {
155
159
  asset.tree = createModulesTree(asset.modules);
156
160
  return result;
157
161
  }, {});
158
- return Object.entries(assets).map(([filename, asset]) => ({
159
- label: filename,
160
- isAsset: true,
161
- // Not using `asset.size` here provided by Webpack because it can be very confusing when `UglifyJsPlugin` is used.
162
- // In this case all module sizes from stats file will represent unminified module sizes, but `asset.size` will
163
- // be the size of minified bundle.
164
- // Using `asset.size` only if current asset doesn't contain any modules (resulting size equals 0)
165
- statSize: asset.tree.size || asset.size,
166
- parsedSize: asset.parsedSize,
167
- gzipSize: asset.gzipSize,
168
- groups: _.invokeMap(asset.tree.children, 'toChartData')
169
- }));
162
+ const chunkToInitialByEntrypoint = getChunkToInitialByEntrypoint(bundleStats);
163
+ return Object.entries(assets).map(([filename, asset]) => {
164
+ var _chunkToInitialByEntr;
165
+
166
+ return {
167
+ label: filename,
168
+ isAsset: true,
169
+ // Not using `asset.size` here provided by Webpack because it can be very confusing when `UglifyJsPlugin` is used.
170
+ // In this case all module sizes from stats file will represent unminified module sizes, but `asset.size` will
171
+ // be the size of minified bundle.
172
+ // Using `asset.size` only if current asset doesn't contain any modules (resulting size equals 0)
173
+ statSize: asset.tree.size || asset.size,
174
+ parsedSize: asset.parsedSize,
175
+ gzipSize: asset.gzipSize,
176
+ groups: _.invokeMap(asset.tree.children, 'toChartData'),
177
+ isInitialByEntrypoint: (_chunkToInitialByEntr = chunkToInitialByEntrypoint[filename]) !== null && _chunkToInitialByEntr !== void 0 ? _chunkToInitialByEntr : {}
178
+ };
179
+ });
170
180
  }
171
181
 
172
182
  function readStatsFromFile(filename) {
173
- return JSON.parse(fs.readFileSync(filename, 'utf8'));
183
+ return parseChunked(fs.createReadStream(filename, {
184
+ encoding: 'utf8'
185
+ }));
174
186
  }
175
187
 
176
188
  function getChildAssetBundles(bundleStats, assetName) {
@@ -200,4 +212,23 @@ function createModulesTree(modules) {
200
212
  modules.forEach(module => root.addModule(module));
201
213
  root.mergeNestedFolders();
202
214
  return root;
203
- }
215
+ }
216
+
217
+ function getChunkToInitialByEntrypoint(bundleStats) {
218
+ if (bundleStats == null) {
219
+ return {};
220
+ }
221
+
222
+ const chunkToEntrypointInititalMap = {};
223
+ Object.values(bundleStats.entrypoints || {}).forEach(entrypoint => {
224
+ for (const asset of entrypoint.assets) {
225
+ var _chunkToEntrypointIni;
226
+
227
+ chunkToEntrypointInititalMap[asset.name] = (_chunkToEntrypointIni = chunkToEntrypointInititalMap[asset.name]) !== null && _chunkToEntrypointIni !== void 0 ? _chunkToEntrypointIni : {};
228
+ chunkToEntrypointInititalMap[asset.name][entrypoint.name] = true;
229
+ }
230
+ });
231
+ return chunkToEntrypointInititalMap;
232
+ }
233
+
234
+ ;
@@ -64,45 +64,47 @@ if (mode === 'server') {
64
64
  if (!SIZES.has(defaultSizes)) showHelp(`Invalid default sizes option. Possible values are: ${[...SIZES].join(', ')}`);
65
65
  bundleStatsFile = resolve(bundleStatsFile);
66
66
  if (!bundleDir) bundleDir = dirname(bundleStatsFile);
67
- let bundleStats;
68
-
69
- try {
70
- bundleStats = analyzer.readStatsFromFile(bundleStatsFile);
71
- } catch (err) {
72
- logger.error(`Couldn't read webpack bundle stats from "${bundleStatsFile}":\n${err}`);
73
- logger.debug(err.stack);
74
- process.exit(1);
75
- }
76
-
77
- if (mode === 'server') {
78
- viewer.startServer(bundleStats, {
79
- openBrowser,
80
- port,
81
- host,
82
- defaultSizes,
83
- reportTitle,
84
- bundleDir,
85
- excludeAssets,
86
- logger: new Logger(logLevel),
87
- analyzerUrl: utils.defaultAnalyzerUrl
88
- });
89
- } else if (mode === 'static') {
90
- viewer.generateReport(bundleStats, {
91
- openBrowser,
92
- reportFilename: resolve(reportFilename || 'report.html'),
93
- reportTitle,
94
- defaultSizes,
95
- bundleDir,
96
- excludeAssets,
97
- logger: new Logger(logLevel)
98
- });
99
- } else if (mode === 'json') {
100
- viewer.generateJSONReport(bundleStats, {
101
- reportFilename: resolve(reportFilename || 'report.json'),
102
- bundleDir,
103
- excludeAssets,
104
- logger: new Logger(logLevel)
105
- });
67
+ parseAndAnalyse(bundleStatsFile);
68
+
69
+ async function parseAndAnalyse(bundleStatsFile) {
70
+ try {
71
+ const bundleStats = await analyzer.readStatsFromFile(bundleStatsFile);
72
+
73
+ if (mode === 'server') {
74
+ viewer.startServer(bundleStats, {
75
+ openBrowser,
76
+ port,
77
+ host,
78
+ defaultSizes,
79
+ reportTitle,
80
+ bundleDir,
81
+ excludeAssets,
82
+ logger: new Logger(logLevel),
83
+ analyzerUrl: utils.defaultAnalyzerUrl
84
+ });
85
+ } else if (mode === 'static') {
86
+ viewer.generateReport(bundleStats, {
87
+ openBrowser,
88
+ reportFilename: resolve(reportFilename || 'report.html'),
89
+ reportTitle,
90
+ defaultSizes,
91
+ bundleDir,
92
+ excludeAssets,
93
+ logger: new Logger(logLevel)
94
+ });
95
+ } else if (mode === 'json') {
96
+ viewer.generateJSONReport(bundleStats, {
97
+ reportFilename: resolve(reportFilename || 'report.json'),
98
+ bundleDir,
99
+ excludeAssets,
100
+ logger: new Logger(logLevel)
101
+ });
102
+ }
103
+ } catch (err) {
104
+ logger.error(`Couldn't read webpack bundle stats from "${bundleStatsFile}":\n${err}`);
105
+ logger.debug(err.stack);
106
+ process.exit(1);
107
+ }
106
108
  }
107
109
 
108
110
  function showHelp(error) {
package/lib/template.js CHANGED
@@ -45,6 +45,7 @@ function renderViewer({
45
45
  title,
46
46
  enableWebSocket,
47
47
  chartData,
48
+ entrypoints,
48
49
  defaultSizes,
49
50
  mode
50
51
  } = {}) {
@@ -66,6 +67,7 @@ function renderViewer({
66
67
  <div id="app"></div>
67
68
  <script>
68
69
  window.chartData = ${escapeJson(chartData)};
70
+ window.entrypoints = ${escapeJson(entrypoints)};
69
71
  window.defaultSizes = ${escapeJson(defaultSizes)};
70
72
  </script>
71
73
  </body>
package/lib/viewer.js CHANGED
@@ -42,6 +42,7 @@ module.exports = {
42
42
  startServer,
43
43
  generateReport,
44
44
  generateJSONReport,
45
+ getEntrypoints,
45
46
  // deprecated
46
47
  start: startServer
47
48
  };
@@ -63,6 +64,7 @@ async function startServer(bundleStats, opts) {
63
64
  excludeAssets
64
65
  };
65
66
  let chartData = getChartData(analyzerOpts, bundleStats, bundleDir);
67
+ const entrypoints = getEntrypoints(bundleStats);
66
68
  if (!chartData) return;
67
69
  const sirvMiddleware = sirv(`${projectRoot}/public`, {
68
70
  // disables caching and traverse the file system on every request
@@ -74,6 +76,7 @@ async function startServer(bundleStats, opts) {
74
76
  mode: 'server',
75
77
  title: resolveTitle(reportTitle),
76
78
  chartData,
79
+ entrypoints,
77
80
  defaultSizes,
78
81
  enableWebSocket: true
79
82
  });
@@ -145,11 +148,13 @@ async function generateReport(bundleStats, opts) {
145
148
  logger,
146
149
  excludeAssets
147
150
  }, bundleStats, bundleDir);
151
+ const entrypoints = getEntrypoints(bundleStats);
148
152
  if (!chartData) return;
149
153
  const reportHtml = renderViewer({
150
154
  mode: 'static',
151
155
  title: resolveTitle(reportTitle),
152
156
  chartData,
157
+ entrypoints,
153
158
  defaultSizes,
154
159
  enableWebSocket: false
155
160
  });
@@ -204,4 +209,12 @@ function getChartData(analyzerOpts, ...args) {
204
209
  }
205
210
 
206
211
  return chartData;
212
+ }
213
+
214
+ function getEntrypoints(bundleStats) {
215
+ if (bundleStats === null || bundleStats === undefined) {
216
+ return [];
217
+ }
218
+
219
+ return Object.values(bundleStats.entrypoints || {}).map(entrypoint => entrypoint.name);
207
220
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webpack-bundle-analyzer",
3
- "version": "4.6.1",
3
+ "version": "4.8.0",
4
4
  "description": "Webpack plugin and CLI utility that represents bundle content as convenient interactive zoomable treemap",
5
5
  "author": "Yury Grunin <grunin.ya@ya.ru>",
6
6
  "license": "MIT",
@@ -32,6 +32,7 @@
32
32
  "lib"
33
33
  ],
34
34
  "dependencies": {
35
+ "@discoveryjs/json-ext": "0.5.7",
35
36
  "acorn": "^8.0.4",
36
37
  "acorn-walk": "^8.0.0",
37
38
  "chalk": "^4.1.0",
@@ -84,7 +85,7 @@
84
85
  "url-loader": "4.1.1",
85
86
  "webpack": "5.37.1",
86
87
  "webpack-cli": "3.3.12",
87
- "webpack-dev-server": "3.11.2"
88
+ "webpack-dev-server": "3.11.3"
88
89
  },
89
90
  "keywords": [
90
91
  "webpack",