webpack-bundle-analyzer 5.1.1 → 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 CHANGED
@@ -24,13 +24,11 @@ yarn add -D webpack-bundle-analyzer
24
24
  <h2 align="center">Usage (as a plugin)</h2>
25
25
 
26
26
  ```js
27
- const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
27
+ const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
28
28
 
29
29
  module.exports = {
30
- plugins: [
31
- new BundleAnalyzerPlugin()
32
- ]
33
- }
30
+ plugins: [new BundleAnalyzerPlugin()],
31
+ };
34
32
  ```
35
33
 
36
34
  It will create an interactive treemap visualization of the contents of all your bundles.
@@ -39,36 +37,38 @@ It will create an interactive treemap visualization of the contents of all your
39
37
 
40
38
  This module will help you:
41
39
 
42
- 1. Realize what's *really* inside your bundle
40
+ 1. Realize what's _really_ inside your bundle
43
41
  2. Find out what modules make up the most of its size
44
42
  3. Find modules that got there by mistake
45
43
  4. Optimize it!
46
44
 
47
45
  And the best thing is it supports minified bundles! It parses them to get real size of bundled modules.
48
- And it also shows their gzipped or Brotli sizes!
46
+ And it also shows their gzipped, Brotli, or Zstandard sizes!
49
47
 
50
48
  <h2 align="center">Options (for plugin)</h2>
51
49
 
50
+ <!-- eslint-skip -->
51
+
52
52
  ```js
53
53
  new BundleAnalyzerPlugin(options?: object)
54
54
  ```
55
55
 
56
- |Name|Type|Description|
57
- |:--:|:--:|:----------|
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`. |
59
- |**`analyzerHost`**|`{String}`|Default: `127.0.0.1`. Host 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 |
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.|
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).|
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.|
64
- |**`defaultSizes`**|One of: `stat`, `parsed`, `gzip`, `brotli`|Default: `parsed`. Module sizes to show in report by default. [Size definitions](#size-definitions) section describes what these values mean.|
65
- |**`compressionAlgorithm`**|One of: `gzip`, `brotli`|Default: `gzip`. Compression type used to calculate the compressed module sizes.|
66
- |**`openAnalyzer`**|`{Boolean}`|Default: `true`. Automatically open report in default browser.|
67
- |**`generateStatsFile`**|`{Boolean}`|Default: `false`. If `true`, webpack stats JSON file will be generated in bundle output directory|
68
- |**`statsFilename`**|`{String}`|Default: `stats.json`. Name of webpack stats JSON file that will be generated if `generateStatsFile` is `true`. It can be either an absolute path or a path relative to a bundle output directory (which is output.path in webpack config).|
69
- |**`statsOptions`**|`null` or `{Object}`|Default: `null`. Options for `stats.toJson()` method. For example you can exclude sources of your modules from stats file with `source: false` option. [See more options here](https://webpack.js.org/configuration/stats/). |
70
- |**`excludeAssets`**|`{null\|pattern\|pattern[]}` where `pattern` equals to `{String\|RegExp\|function}`|Default: `null`. Patterns that will be used to match against asset names to exclude them from the report. If pattern is a string it will be converted to RegExp via `new RegExp(str)`. If pattern is a function it should have the following signature `(assetName: string) => boolean` and should return `true` to *exclude* matching asset. If multiple patterns are provided asset should match at least one of them to be excluded. |
71
- |**`logLevel`**|One of: `info`, `warn`, `error`, `silent`|Default: `info`. Used to control how much details the plugin outputs.|
56
+ | Name | Type | Description |
57
+ | :------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
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`. |
59
+ | **`analyzerHost`** | `{String}` | Default: `127.0.0.1`. Host 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 |
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. |
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). |
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. |
64
+ | **`defaultSizes`** | One of: `stat`, `parsed`, `gzip`, `brotli` | Default: `parsed`. Module sizes to show in report by default. [Size definitions](#size-definitions) section describes what these values mean. |
65
+ | **`compressionAlgorithm`** | One of: `gzip`, `brotli`, `zstd` | Default: `gzip`. Compression type used to calculate the compressed module sizes. |
66
+ | **`openAnalyzer`** | `{Boolean}` | Default: `true`. Automatically open report in default browser. |
67
+ | **`generateStatsFile`** | `{Boolean}` | Default: `false`. If `true`, webpack stats JSON file will be generated in bundle output directory |
68
+ | **`statsFilename`** | `{String}` | Default: `stats.json`. Name of webpack stats JSON file that will be generated if `generateStatsFile` is `true`. It can be either an absolute path or a path relative to a bundle output directory (which is output.path in webpack config). |
69
+ | **`statsOptions`** | `null` or `{Object}` | Default: `null`. Options for `stats.toJson()` method. For example you can exclude sources of your modules from stats file with `source: false` option. [See more options here](https://webpack.js.org/configuration/stats/). |
70
+ | **`excludeAssets`** | `{null\|pattern\|pattern[]}` where `pattern` equals to `{String\|RegExp\|function}` | Default: `null`. Patterns that will be used to match against asset names to exclude them from the report. If pattern is a string it will be converted to RegExp via `new RegExp(str)`. If pattern is a function it should have the following signature `(assetName: string) => boolean` and should return `true` to _exclude_ matching asset. If multiple patterns are provided asset should match at least one of them to be excluded. |
71
+ | **`logLevel`** | One of: `info`, `warn`, `error`, `silent` | Default: `info`. Used to control how much details the plugin outputs. |
72
72
 
73
73
  <h2 align="center">Usage (as a CLI utility)</h2>
74
74
 
@@ -122,9 +122,9 @@ Directory containing all generated bundles.
122
122
  -r, --report <file> Path to bundle report file that will be generated in `static` mode. (default: report.html)
123
123
  -t, --title <title> String to use in title element of html report. (default: pretty printed current date)
124
124
  -s, --default-sizes <type> Module sizes to show in treemap by default.
125
- Possible values: stat, parsed, gzip, brotli (default: parsed)
125
+ Possible values: stat, parsed, gzip, brotli, zstd (default: parsed)
126
126
  --compression-algorithm <type> Compression algorithm that will be used to calculate the compressed module sizes.
127
- Possible values: gzip, brotli (default: gzip)
127
+ Possible values: gzip, brotli, zstd (default: gzip)
128
128
  -O, --no-open Don't open report in default browser automatically.
129
129
  -e, --exclude <regexp> Assets that should be excluded from the report.
130
130
  Can be specified multiple times.
@@ -158,6 +158,10 @@ This is the size of running the parsed bundles/modules through gzip compression.
158
158
 
159
159
  This is the size of running the parsed bundles/modules through Brotli compression.
160
160
 
161
+ ### `zstd`
162
+
163
+ This is the size of running the parsed bundles/modules through Zstandard compression. (Node.js 22.15.0+ is required for this feature)
164
+
161
165
  <h2 align="center">Selecting Which Chunks to Display</h2>
162
166
 
163
167
  When opened, the report displays all of the Webpack chunks for your project. It's possible to filter to a more specific list of chunks by using the sidebar or the chunk context menu.
@@ -170,19 +174,21 @@ The Sidebar Menu can be opened by clicking the `>` button at the top left of the
170
174
 
171
175
  The Chunk Context Menu can be opened by right-clicking or `Ctrl`-clicking on a specific chunk in the report. It provides the following options:
172
176
 
173
- * **Hide chunk:** Hides the selected chunk
174
- * **Hide all other chunks:** Hides all chunks besides the selected one
175
- * **Show all chunks:** Un-hides any hidden chunks, returning the report to its initial, unfiltered view
177
+ - **Hide chunk:** Hides the selected chunk
178
+ - **Hide all other chunks:** Hides all chunks besides the selected one
179
+ - **Show all chunks:** Un-hides any hidden chunks, returning the report to its initial, unfiltered view
176
180
 
177
181
  <h2 align="center">Troubleshooting</h2>
178
182
 
179
183
  ### I don't see `gzip` or `parsed` sizes, it only shows `stat` size
180
184
 
181
185
  It happens when `webpack-bundle-analyzer` analyzes files that don't actually exist in your file system, for example when you work with `webpack-dev-server` that keeps all the files in RAM. If you use `webpack-bundle-analyzer` as a plugin you won't get any errors, however if you run it via CLI you get the error message in terminal:
186
+
182
187
  ```
183
188
  Error parsing bundle asset "your_bundle_name.bundle.js": no such file
184
189
  No bundles were parsed. Analyzer will show only original module sizes from stats file.
185
190
  ```
191
+
186
192
  To get more information about it you can read [issue #147](https://github.com/webpack/webpack-bundle-analyzer/issues/147).
187
193
 
188
194
  <h2 align="center">Other tools</h2>
@@ -210,16 +216,12 @@ To get more information about it you can read [issue #147](https://github.com/we
210
216
  <tbody>
211
217
  </table>
212
218
 
213
-
214
219
  [npm]: https://img.shields.io/npm/v/webpack-bundle-analyzer.svg
215
220
  [npm-url]: https://npmjs.com/package/webpack-bundle-analyzer
216
-
217
221
  [node]: https://img.shields.io/node/v/webpack-bundle-analyzer.svg
218
222
  [node-url]: https://nodejs.org
219
-
220
223
  [tests]: https://github.com/webpack/webpack-bundle-analyzer/actions/workflows/main.yml/badge.svg
221
224
  [tests-url]: https://github.com/webpack/webpack-bundle-analyzer/actions/workflows/main.yml
222
-
223
225
  [downloads]: https://img.shields.io/npm/dt/webpack-bundle-analyzer.svg
224
226
  [downloads-url]: https://npmjs.com/package/webpack-bundle-analyzer
225
227
 
@@ -1,58 +1,120 @@
1
1
  "use strict";
2
2
 
3
- const fs = require('fs');
4
- const path = require('path');
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
5
  const {
6
6
  bold
7
- } = require('picocolors');
8
- const Logger = require('./Logger');
9
- const viewer = require('./viewer');
10
- const utils = require('./utils');
7
+ } = require("picocolors");
8
+ const Logger = require("./Logger");
11
9
  const {
12
10
  writeStats
13
- } = require('./statsUtils');
11
+ } = require("./statsUtils");
12
+ const utils = require("./utils");
13
+ const viewer = require("./viewer");
14
+
15
+ /** @typedef {import("net").AddressInfo} AddressInfo */
16
+ /** @typedef {import("webpack").Compiler} Compiler */
17
+ /** @typedef {import("webpack").OutputFileSystem} OutputFileSystem */
18
+ /** @typedef {import("webpack").Stats} Stats */
19
+ /** @typedef {import("webpack").StatsOptions} StatsOptions */
20
+ /** @typedef {import("webpack").StatsAsset} StatsAsset */
21
+ /** @typedef {import("webpack").StatsCompilation} StatsCompilation */
22
+ /** @typedef {import("./sizeUtils").Algorithm} CompressionAlgorithm */
23
+ /** @typedef {import("./Logger").Level} LogLever */
24
+ /** @typedef {import("./viewer").ViewerServerObj} ViewerServerObj */
25
+
26
+ /** @typedef {string | boolean | StatsOptions} PluginStatsOptions */
27
+
28
+ // eslint-disable-next-line jsdoc/reject-any-type
29
+ /** @typedef {any} EXPECTED_ANY */
30
+
31
+ /** @typedef {"static" | "json" | "server" | "disabled"} Mode */
32
+ /** @typedef {string | RegExp | ((asset: string) => void)} Pattern */
33
+ /** @typedef {null | Pattern | Pattern[]} ExcludeAssets */
34
+ /** @typedef {"stat" | "parsed" | "gzip" | "brotli" | "zstd"} Sizes */
35
+ /** @typedef {string | (() => string)} ReportTitle */
36
+ /** @typedef {(options: { listenHost: string, listenPort: number, boundAddress: string | AddressInfo | null }) => string} AnalyzerUrl */
37
+
38
+ /**
39
+ * @typedef {object} Options
40
+ * @property {Mode=} analyzerMode analyzer mode
41
+ * @property {string=} analyzerHost analyzer host
42
+ * @property {"auto" | number=} analyzerPort analyzer port
43
+ * @property {CompressionAlgorithm=} compressionAlgorithm compression algorithm
44
+ * @property {string | null=} reportFilename report filename
45
+ * @property {ReportTitle=} reportTitle report title
46
+ * @property {Sizes=} defaultSizes default sizes
47
+ * @property {boolean=} openAnalyzer open analyzer
48
+ * @property {boolean=} generateStatsFile generate stats file
49
+ * @property {string=} statsFilename stats filename
50
+ * @property {PluginStatsOptions=} statsOptions stats options
51
+ * @property {ExcludeAssets=} excludeAssets exclude assets
52
+ * @property {LogLever=} logLevel exclude assets
53
+ * @property {boolean=} startAnalyzer start analyzer
54
+ * @property {AnalyzerUrl=} analyzerUrl start analyzer
55
+ */
56
+
14
57
  class BundleAnalyzerPlugin {
58
+ /**
59
+ * @param {Options=} opts options
60
+ */
15
61
  constructor(opts = {}) {
62
+ /** @type {Required<Omit<Options, "analyzerPort" | "statsOptions">> & { analyzerPort: number, statsOptions: undefined | PluginStatsOptions }} */
16
63
  this.opts = {
17
- analyzerMode: 'server',
18
- analyzerHost: '127.0.0.1',
19
- compressionAlgorithm: 'gzip',
64
+ analyzerMode: "server",
65
+ analyzerHost: "127.0.0.1",
66
+ compressionAlgorithm: "gzip",
20
67
  reportFilename: null,
21
68
  reportTitle: utils.defaultTitle,
22
- defaultSizes: 'parsed',
69
+ defaultSizes: "parsed",
23
70
  openAnalyzer: true,
24
71
  generateStatsFile: false,
25
- statsFilename: 'stats.json',
26
- statsOptions: null,
72
+ statsFilename: "stats.json",
73
+ statsOptions: undefined,
27
74
  excludeAssets: null,
28
- logLevel: 'info',
29
- // deprecated
75
+ logLevel: "info",
76
+ // TODO deprecated
30
77
  startAnalyzer: true,
31
78
  analyzerUrl: utils.defaultAnalyzerUrl,
32
79
  ...opts,
33
- analyzerPort: 'analyzerPort' in opts ? opts.analyzerPort === 'auto' ? 0 : opts.analyzerPort : 8888
80
+ analyzerPort: opts.analyzerPort === "auto" ? 0 : opts.analyzerPort ?? 8888
34
81
  };
82
+
83
+ /** @type {Compiler | null} */
84
+ this.compiler = null;
85
+ /** @type {Promise<ViewerServerObj> | null} */
35
86
  this.server = null;
36
87
  this.logger = new Logger(this.opts.logLevel);
37
88
  }
89
+
90
+ /**
91
+ * @param {Compiler} compiler compiler
92
+ */
38
93
  apply(compiler) {
39
94
  this.compiler = compiler;
95
+
96
+ /**
97
+ * @param {Stats} stats stats
98
+ * @param {(err?: Error) => void} callback callback
99
+ */
40
100
  const done = (stats, callback) => {
41
- callback = callback || (() => {});
101
+ callback ||= () => {};
102
+
103
+ /** @type {(() => Promise<void>)[]} */
42
104
  const actions = [];
43
105
  if (this.opts.generateStatsFile) {
44
106
  actions.push(() => this.generateStatsFile(stats.toJson(this.opts.statsOptions)));
45
107
  }
46
108
 
47
109
  // Handling deprecated `startAnalyzer` flag
48
- if (this.opts.analyzerMode === 'server' && !this.opts.startAnalyzer) {
49
- this.opts.analyzerMode = 'disabled';
110
+ if (this.opts.analyzerMode === "server" && !this.opts.startAnalyzer) {
111
+ this.opts.analyzerMode = "disabled";
50
112
  }
51
- if (this.opts.analyzerMode === 'server') {
113
+ if (this.opts.analyzerMode === "server") {
52
114
  actions.push(() => this.startAnalyzerServer(stats.toJson()));
53
- } else if (this.opts.analyzerMode === 'static') {
115
+ } else if (this.opts.analyzerMode === "static") {
54
116
  actions.push(() => this.generateStaticReport(stats.toJson()));
55
- } else if (this.opts.analyzerMode === 'json') {
117
+ } else if (this.opts.analyzerMode === "json") {
56
118
  actions.push(() => this.generateJSONReport(stats.toJson()));
57
119
  }
58
120
  if (actions.length) {
@@ -61,8 +123,8 @@ class BundleAnalyzerPlugin {
61
123
  try {
62
124
  await Promise.all(actions.map(action => action()));
63
125
  callback();
64
- } catch (e) {
65
- callback(e);
126
+ } catch (err) {
127
+ callback(/** @type {Error} */err);
66
128
  }
67
129
  });
68
130
  } else {
@@ -70,23 +132,35 @@ class BundleAnalyzerPlugin {
70
132
  }
71
133
  };
72
134
  if (compiler.hooks) {
73
- compiler.hooks.done.tapAsync('webpack-bundle-analyzer', done);
135
+ compiler.hooks.done.tapAsync("webpack-bundle-analyzer", done);
74
136
  } else {
75
- compiler.plugin('done', done);
137
+ // @ts-expect-error old webpack@4 API
138
+ compiler.plugin("done", done);
76
139
  }
77
140
  }
141
+
142
+ /**
143
+ * @param {StatsCompilation} stats stats
144
+ * @returns {Promise<void>}
145
+ */
78
146
  async generateStatsFile(stats) {
79
- const statsFilepath = path.resolve(this.compiler.outputPath, this.opts.statsFilename);
147
+ const statsFilepath = path.resolve(/** @type {Compiler} */
148
+ this.compiler.outputPath, this.opts.statsFilename);
80
149
  await fs.promises.mkdir(path.dirname(statsFilepath), {
81
150
  recursive: true
82
151
  });
83
152
  try {
84
153
  await writeStats(stats, statsFilepath);
85
- this.logger.info(`${bold('Webpack Bundle Analyzer')} saved stats file to ${bold(statsFilepath)}`);
154
+ this.logger.info(`${bold("Webpack Bundle Analyzer")} saved stats file to ${bold(statsFilepath)}`);
86
155
  } catch (error) {
87
- this.logger.error(`${bold('Webpack Bundle Analyzer')} error saving stats file to ${bold(statsFilepath)}: ${error}`);
156
+ this.logger.error(`${bold("Webpack Bundle Analyzer")} error saving stats file to ${bold(statsFilepath)}: ${error}`);
88
157
  }
89
158
  }
159
+
160
+ /**
161
+ * @param {StatsCompilation} stats stats
162
+ * @returns {Promise<void>}
163
+ */
90
164
  async startAnalyzerServer(stats) {
91
165
  if (this.server) {
92
166
  (await this.server).updateChartData(stats);
@@ -105,19 +179,31 @@ class BundleAnalyzerPlugin {
105
179
  });
106
180
  }
107
181
  }
182
+
183
+ /**
184
+ * @param {StatsCompilation} stats stats
185
+ * @returns {Promise<void>}
186
+ */
108
187
  async generateJSONReport(stats) {
109
188
  await viewer.generateJSONReport(stats, {
110
- reportFilename: path.resolve(this.compiler.outputPath, this.opts.reportFilename || 'report.json'),
189
+ reportFilename: path.resolve(/** @type {Compiler} */
190
+ this.compiler.outputPath, this.opts.reportFilename || "report.json"),
111
191
  compressionAlgorithm: this.opts.compressionAlgorithm,
112
192
  bundleDir: this.getBundleDirFromCompiler(),
113
193
  logger: this.logger,
114
194
  excludeAssets: this.opts.excludeAssets
115
195
  });
116
196
  }
197
+
198
+ /**
199
+ * @param {StatsCompilation} stats stats
200
+ * @returns {Promise<void>}
201
+ */
117
202
  async generateStaticReport(stats) {
118
203
  await viewer.generateReport(stats, {
119
204
  openBrowser: this.opts.openAnalyzer,
120
- reportFilename: path.resolve(this.compiler.outputPath, this.opts.reportFilename || 'report.html'),
205
+ reportFilename: path.resolve(/** @type {Compiler} */
206
+ this.compiler.outputPath, this.opts.reportFilename || "report.html"),
121
207
  reportTitle: this.opts.reportTitle,
122
208
  compressionAlgorithm: this.opts.compressionAlgorithm,
123
209
  bundleDir: this.getBundleDirFromCompiler(),
@@ -127,18 +213,20 @@ class BundleAnalyzerPlugin {
127
213
  });
128
214
  }
129
215
  getBundleDirFromCompiler() {
130
- if (typeof this.compiler.outputFileSystem.constructor === 'undefined') {
131
- return this.compiler.outputPath;
216
+ const outputFileSystemConstructor = /** @type {OutputFileSystem} */
217
+ (/** @type {Compiler} */this.compiler.outputFileSystem).constructor;
218
+ if (typeof outputFileSystemConstructor === "undefined") {
219
+ return /** @type {Compiler} */this.compiler.outputPath;
132
220
  }
133
- switch (this.compiler.outputFileSystem.constructor.name) {
134
- case 'MemoryFileSystem':
221
+ switch (outputFileSystemConstructor.name) {
222
+ case "MemoryFileSystem":
135
223
  return null;
136
224
  // Detect AsyncMFS used by Nuxt 2.5 that replaces webpack's MFS during development
137
225
  // Related: #274
138
- case 'AsyncMFS':
226
+ case "AsyncMFS":
139
227
  return null;
140
228
  default:
141
- return this.compiler.outputPath;
229
+ return /** @type {Compiler} */this.compiler.outputPath;
142
230
  }
143
231
  }
144
232
  }
package/lib/Logger.js CHANGED
@@ -1,31 +1,89 @@
1
1
  "use strict";
2
2
 
3
- const LEVELS = ['debug', 'info', 'warn', 'error', 'silent'];
4
- const LEVEL_TO_CONSOLE_METHOD = new Map([['debug', 'log'], ['info', 'log'], ['warn', 'log']]);
3
+ /** @typedef {import("./BundleAnalyzerPlugin").EXPECTED_ANY} EXPECTED_ANY */
4
+
5
+ /** @typedef {"debug" | "info" | "warn" | "error" | "silent"} Level */
6
+
7
+ /** @type {Level[]} */
8
+ const LEVELS = ["debug", "info", "warn", "error", "silent"];
9
+
10
+ /** @type {Map<Level, string>} */
11
+ const LEVEL_TO_CONSOLE_METHOD = new Map([["debug", "log"], ["info", "log"], ["warn", "log"]]);
5
12
  class Logger {
13
+ /** @type {Level[]} */
6
14
  static levels = LEVELS;
7
- static defaultLevel = 'info';
15
+
16
+ /** @type {Level} */
17
+ static defaultLevel = "info";
18
+
19
+ /**
20
+ * @param {Level=} level level
21
+ */
8
22
  constructor(level = Logger.defaultLevel) {
23
+ /** @type {Set<Level>} */
9
24
  this.activeLevels = new Set();
10
25
  this.setLogLevel(level);
11
26
  }
27
+
28
+ /**
29
+ * @param {Level} level level
30
+ */
12
31
  setLogLevel(level) {
13
32
  const levelIndex = LEVELS.indexOf(level);
14
- if (levelIndex === -1) throw new Error(`Invalid log level "${level}". Use one of these: ${LEVELS.join(', ')}`);
33
+ if (levelIndex === -1) {
34
+ throw new Error(`Invalid log level "${level}". Use one of these: ${LEVELS.join(", ")}`);
35
+ }
15
36
  this.activeLevels.clear();
16
37
  for (const [i, level] of LEVELS.entries()) {
17
38
  if (i >= levelIndex) this.activeLevels.add(level);
18
39
  }
19
40
  }
41
+
42
+ /**
43
+ * @template {EXPECTED_ANY[]} T
44
+ * @param {T} args args
45
+ */
46
+ debug(...args) {
47
+ if (!this.activeLevels.has("debug")) return;
48
+ this._log("debug", ...args);
49
+ }
50
+
51
+ /**
52
+ * @template {EXPECTED_ANY[]} T
53
+ * @param {T} args args
54
+ */
55
+ info(...args) {
56
+ if (!this.activeLevels.has("info")) return;
57
+ this._log("info", ...args);
58
+ }
59
+
60
+ /**
61
+ * @template {EXPECTED_ANY[]} T
62
+ * @param {T} args args
63
+ */
64
+ error(...args) {
65
+ if (!this.activeLevels.has("error")) return;
66
+ this._log("error", ...args);
67
+ }
68
+
69
+ /**
70
+ * @template {EXPECTED_ANY[]} T
71
+ * @param {T} args args
72
+ */
73
+ warn(...args) {
74
+ if (!this.activeLevels.has("warn")) return;
75
+ this._log("warn", ...args);
76
+ }
77
+
78
+ /**
79
+ * @template {EXPECTED_ANY[]} T
80
+ * @param {Level} level level
81
+ * @param {T} args args
82
+ */
20
83
  _log(level, ...args) {
21
- console[LEVEL_TO_CONSOLE_METHOD.get(level) || level](...args);
84
+ // eslint-disable-next-line no-console
85
+ console[(/** @type {Exclude<Level, "silent">} */
86
+ LEVEL_TO_CONSOLE_METHOD.get(level) || level)](...args);
22
87
  }
23
88
  }
24
- ;
25
- LEVELS.forEach(level => {
26
- if (level === 'silent') return;
27
- Logger.prototype[level] = function (...args) {
28
- if (this.activeLevels.has(level)) this._log(level, ...args);
29
- };
30
- });
31
89
  module.exports = Logger;