webpack-bundle-analyzer 4.0.0 → 4.4.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,7 +12,42 @@ _Note: Gaps between patch versions are faulty, broken or test releases._
12
12
 
13
13
  ## UNRELEASED
14
14
 
15
- <!-- Add changelog entries for new changes under this section -->
15
+ ## 4.4.0
16
+
17
+ * **Improvement**
18
+ * Keep treemap labels visible during zooming animations for better user experience ([#414](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/414) by [@
19
+ stanislawosinski](https://github.com/stanislawosinski))
20
+
21
+ * **Bug Fix**
22
+ * Don't show an empty tooltip when hovering over the FoamTree attribution group or between top-level groups ([#413](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/413) by [@
23
+ stanislawosinski](https://github.com/stanislawosinski))
24
+
25
+ * **Internal**
26
+ * Upgrade FoamTree to version 3.5.0, replace vendor dependency with an NPM package ([#412](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/412) by [@
27
+ stanislawosinski](https://github.com/stanislawosinski))
28
+
29
+ ## 4.3.0
30
+
31
+ * **Improvement**
32
+ * Replace express with builtin node server, reducing number of dependencies ([#398](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/398) by [@TrySound](https://github.com/TrySound))
33
+ * Move `filesize` to dev dependencies, reducing number of dependencies ([#401](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/401) by [@realityking](https://github.com/realityking))
34
+
35
+ * **Internal**
36
+ * Replace Travis with GitHub actions ([#402](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/402) by [@valscion](https://github.com/valscion))
37
+
38
+ ## 4.2.0
39
+
40
+ * **Improvement**
41
+ * A number of improvements to reduce the number of dependencies ([#391](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/391), [#396](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/396), [#397](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/397))
42
+
43
+ * **Bug Fix**
44
+ * Prevent crashes for bundles generated from webpack array configs. ([#394](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/394) by [@ctavan](https://github.com/ctavan))
45
+ * Fix `non-asset` assets causing analyze failure. ([#385](https://github.com/webpack-contrib/webpack-bundle-analyzer/issues/385) by [@ZKHelloworld](https://github.com/ZKHelloworld))
46
+
47
+ ## 4.1.0
48
+
49
+ * **Improvement**
50
+ * Significantly speed up generation of `stats.json` file (see `generateStatsFile` option).
16
51
 
17
52
  ## 4.0.0
18
53
 
package/README.md CHANGED
@@ -178,6 +178,9 @@ Analyzer will use module sizes from stats file.
178
178
  ```
179
179
  To get more information about it you can read [issue #147](https://github.com/webpack-contrib/webpack-bundle-analyzer/issues/147).
180
180
 
181
+ <h2 align="center">Other tools</h2>
182
+
183
+ - [Statoscope](https://github.com/smelukov/statoscope/blob/master/packages/ui-webpack/README.md) - Webpack bundle analyzing tool to find out why a certain module was bundled (and more features, including interactive treemap)
181
184
 
182
185
  <h2 align="center">Maintainers</h2>
183
186
 
@@ -1,11 +1,9 @@
1
1
  "use strict";
2
2
 
3
- const bfj = require('bfj');
3
+ const fs = require('fs');
4
4
 
5
5
  const path = require('path');
6
6
 
7
- const mkdir = require('mkdirp');
8
-
9
7
  const {
10
8
  bold
11
9
  } = require('chalk');
@@ -16,6 +14,10 @@ const viewer = require('./viewer');
16
14
 
17
15
  const utils = require('./utils');
18
16
 
17
+ const {
18
+ writeStats
19
+ } = require('./statsUtils');
20
+
19
21
  class BundleAnalyzerPlugin {
20
22
  constructor(opts = {}) {
21
23
  this.opts = {
@@ -88,17 +90,12 @@ class BundleAnalyzerPlugin {
88
90
 
89
91
  async generateStatsFile(stats) {
90
92
  const statsFilepath = path.resolve(this.compiler.outputPath, this.opts.statsFilename);
91
- mkdir.sync(path.dirname(statsFilepath));
93
+ await fs.promises.mkdir(path.dirname(statsFilepath), {
94
+ recursive: true
95
+ });
92
96
 
93
97
  try {
94
- await bfj.write(statsFilepath, stats, {
95
- space: 2,
96
- promises: 'ignore',
97
- buffers: 'ignore',
98
- maps: 'ignore',
99
- iterables: 'ignore',
100
- circular: 'ignore'
101
- });
98
+ await writeStats(stats, statsFilepath);
102
99
  this.logger.info(`${bold('Webpack Bundle Analyzer')} saved stats file to ${bold(statsFilepath)}`);
103
100
  } catch (error) {
104
101
  this.logger.error(`${bold('Webpack Bundle Analyzer')} error saving stats file to ${bold(statsFilepath)}: ${error}`);
package/lib/analyzer.js CHANGED
@@ -42,7 +42,7 @@ function getViewerData(bundleStats, bundleDir, opts) {
42
42
  // leave the 1st one as that is considered the 'root' asset.
43
43
 
44
44
  for (let i = 1; i < children.length; i++) {
45
- bundleStats.children[i].assets.forEach(asset => {
45
+ children[i].assets.forEach(asset => {
46
46
  asset.isChild = true;
47
47
  bundleStats.assets.push(asset);
48
48
  });
@@ -58,9 +58,14 @@ function getViewerData(bundleStats, bundleDir, opts) {
58
58
  } // Picking only `*.js or *.mjs` assets from bundle that has non-empty `chunks` array
59
59
 
60
60
 
61
- bundleStats.assets = _.filter(bundleStats.assets, asset => {
62
- // Removing query part from filename (yes, somebody uses it for some reason and Webpack supports it)
61
+ bundleStats.assets = bundleStats.assets.filter(asset => {
62
+ // Filter out non 'asset' type asset if type is provided (Webpack 5 add a type to indicate asset types)
63
+ if (asset.type && asset.type !== 'asset') {
64
+ return false;
65
+ } // Removing query part from filename (yes, somebody uses it for some reason and Webpack supports it)
63
66
  // See #22
67
+
68
+
64
69
  asset.name = asset.name.replace(FILENAME_QUERY_REGEXP, '');
65
70
  return FILENAME_EXTENSIONS.test(asset.name) && !_.isEmpty(asset.chunks) && isAssetIncluded(asset.name);
66
71
  }); // Trying to parse bundle assets and get real module sizes if `bundleDir` is provided
@@ -85,8 +90,7 @@ function getViewerData(bundleStats, bundleDir, opts) {
85
90
  }
86
91
 
87
92
  bundlesSources[statAsset.name] = _.pick(bundleInfo, 'src', 'runtimeSrc');
88
-
89
- _.assign(parsedModules, bundleInfo.modules);
93
+ Object.assign(parsedModules, bundleInfo.modules);
90
94
  }
91
95
 
92
96
  if (_.isEmpty(bundlesSources)) {
@@ -96,7 +100,7 @@ function getViewerData(bundleStats, bundleDir, opts) {
96
100
  }
97
101
  }
98
102
 
99
- const assets = _.transform(bundleStats.assets, (result, statAsset) => {
103
+ const assets = bundleStats.assets.reduce((result, statAsset) => {
100
104
  // If asset is a childAsset, then calculate appropriate bundle modules by looking through stats.children
101
105
  const assetBundles = statAsset.isChild ? getChildAssetBundles(bundleStats, statAsset.name) : bundleStats;
102
106
  const modules = assetBundles ? getBundleModules(assetBundles) : [];
@@ -149,22 +153,20 @@ function getViewerData(bundleStats, bundleDir, opts) {
149
153
 
150
154
  asset.modules = assetModules;
151
155
  asset.tree = createModulesTree(asset.modules);
156
+ return result;
152
157
  }, {});
153
-
154
- return _.transform(assets, (result, asset, filename) => {
155
- result.push({
156
- label: filename,
157
- isAsset: true,
158
- // Not using `asset.size` here provided by Webpack because it can be very confusing when `UglifyJsPlugin` is used.
159
- // In this case all module sizes from stats file will represent unminified module sizes, but `asset.size` will
160
- // be the size of minified bundle.
161
- // Using `asset.size` only if current asset doesn't contain any modules (resulting size equals 0)
162
- statSize: asset.tree.size || asset.size,
163
- parsedSize: asset.parsedSize,
164
- gzipSize: asset.gzipSize,
165
- groups: _.invokeMap(asset.tree.children, 'toChartData')
166
- });
167
- }, []);
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
+ }));
168
170
  }
169
171
 
170
172
  function readStatsFromFile(filename) {
@@ -172,7 +174,7 @@ function readStatsFromFile(filename) {
172
174
  }
173
175
 
174
176
  function getChildAssetBundles(bundleStats, assetName) {
175
- return _.find(bundleStats.children, c => _(c.assetsByChunkName).values().flatten().includes(assetName));
177
+ return (bundleStats.children || []).find(c => _(c.assetsByChunkName).values().flatten().includes(assetName));
176
178
  }
177
179
 
178
180
  function getBundleModules(bundleStats) {
@@ -182,7 +184,7 @@ function getBundleModules(bundleStats) {
182
184
 
183
185
  function assetHasModule(statAsset, statModule) {
184
186
  // Checking if this module is the part of asset chunks
185
- return _.some(statModule.chunks, moduleChunk => _.includes(statAsset.chunks, moduleChunk));
187
+ return statModule.chunks.some(moduleChunk => statAsset.chunks.includes(moduleChunk));
186
188
  }
187
189
 
188
190
  function isEntryModule(statModule) {
@@ -195,9 +197,7 @@ function isRuntimeModule(statModule) {
195
197
 
196
198
  function createModulesTree(modules) {
197
199
  const root = new Folder('.');
198
-
199
- _.each(modules, module => root.addModule(module));
200
-
200
+ modules.forEach(module => root.addModule(module));
201
201
  root.mergeNestedFolders();
202
202
  return root;
203
203
  }
@@ -6,8 +6,6 @@ const {
6
6
  dirname
7
7
  } = require('path');
8
8
 
9
- const _ = require('lodash');
10
-
11
9
  const commander = require('commander');
12
10
 
13
11
  const {
@@ -113,7 +111,7 @@ function showHelp(error) {
113
111
  }
114
112
 
115
113
  function br(str) {
116
- return `\n${_.repeat(' ', 28)}${str}`;
114
+ return `\n${' '.repeat(28)}${str}`;
117
115
  }
118
116
 
119
117
  function array() {
package/lib/parseUtils.js CHANGED
@@ -112,7 +112,7 @@ function parseBundle(bundlePath) {
112
112
  // features (e.g. `umd` library output) can wrap modules list into additional IIFE.
113
113
 
114
114
 
115
- _.each(args, arg => c(arg, state));
115
+ args.forEach(arg => c(arg, state));
116
116
  }
117
117
 
118
118
  });
@@ -136,8 +136,7 @@ function parseBundle(bundlePath) {
136
136
 
137
137
 
138
138
  function getBundleRuntime(content, modulesLocations) {
139
- const sortedLocations = _(modulesLocations).values().sortBy('start');
140
-
139
+ const sortedLocations = Object.values(modulesLocations || {}).sort((a, b) => a.start - b.start);
141
140
  let result = '';
142
141
  let lastIndex = 0;
143
142
 
@@ -177,11 +176,11 @@ function isSimpleModulesList(node) {
177
176
  }
178
177
 
179
178
  function isModulesHash(node) {
180
- return node.type === 'ObjectExpression' && _(node.properties).map('value').every(isModuleWrapper);
179
+ return node.type === 'ObjectExpression' && node.properties.map(node => node.value).every(isModuleWrapper);
181
180
  }
182
181
 
183
182
  function isModulesArray(node) {
184
- return node.type === 'ArrayExpression' && _.every(node.elements, elem => // Some of array items may be skipped because there is no module with such id
183
+ return node.type === 'ArrayExpression' && node.elements.every(elem => // Some of array items may be skipped because there is no module with such id
185
184
  !elem || isModuleWrapper(elem));
186
185
  }
187
186
 
@@ -213,7 +212,7 @@ function isNumericId(node) {
213
212
 
214
213
  function isChunkIds(node) {
215
214
  // Array of numeric or string ids. Chunk IDs are strings when NamedChunksPlugin is used
216
- return node.type === 'ArrayExpression' && _.every(node.elements, isModuleId);
215
+ return node.type === 'ArrayExpression' && node.elements.every(isModuleId);
217
216
  }
218
217
 
219
218
  function isAsyncChunkPushExpression(node) {
@@ -241,9 +240,10 @@ function getModulesLocations(node) {
241
240
  if (node.type === 'ObjectExpression') {
242
241
  // Modules hash
243
242
  const modulesNodes = node.properties;
244
- return _.transform(modulesNodes, (result, moduleNode) => {
243
+ return modulesNodes.reduce((result, moduleNode) => {
245
244
  const moduleId = moduleNode.key.name || moduleNode.key.value;
246
245
  result[moduleId] = getModuleLocation(moduleNode.value);
246
+ return result;
247
247
  }, {});
248
248
  }
249
249
 
@@ -256,9 +256,12 @@ function getModulesLocations(node) {
256
256
  0;
257
257
  const modulesNodes = isOptimizedArray ? // The modules reside in the `concat()` function call arguments
258
258
  node.arguments[0].elements : node.elements;
259
- return _.transform(modulesNodes, (result, moduleNode, i) => {
260
- if (!moduleNode) return;
261
- result[i + minId] = getModuleLocation(moduleNode);
259
+ return modulesNodes.reduce((result, moduleNode, i) => {
260
+ if (moduleNode) {
261
+ result[i + minId] = getModuleLocation(moduleNode);
262
+ }
263
+
264
+ return result;
262
265
  }, {});
263
266
  }
264
267
 
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+
3
+ const {
4
+ createWriteStream
5
+ } = require('fs');
6
+
7
+ const {
8
+ Readable
9
+ } = require('stream');
10
+
11
+ class StatsSerializeStream extends Readable {
12
+ constructor(stats) {
13
+ super();
14
+ this._indentLevel = 0;
15
+ this._stringifier = this._stringify(stats);
16
+ }
17
+
18
+ get _indent() {
19
+ return ' '.repeat(this._indentLevel);
20
+ }
21
+
22
+ _read() {
23
+ let readMore = true;
24
+
25
+ while (readMore) {
26
+ const {
27
+ value,
28
+ done
29
+ } = this._stringifier.next();
30
+
31
+ if (done) {
32
+ this.push(null);
33
+ readMore = false;
34
+ } else {
35
+ readMore = this.push(value);
36
+ }
37
+ }
38
+ }
39
+
40
+ *_stringify(obj) {
41
+ if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || obj === null) {
42
+ yield JSON.stringify(obj);
43
+ } else if (Array.isArray(obj)) {
44
+ yield '[';
45
+ this._indentLevel++;
46
+ let isFirst = true;
47
+
48
+ for (let item of obj) {
49
+ if (item === undefined) {
50
+ item = null;
51
+ }
52
+
53
+ yield `${isFirst ? '' : ','}\n${this._indent}`;
54
+ yield* this._stringify(item);
55
+ isFirst = false;
56
+ }
57
+
58
+ this._indentLevel--;
59
+ yield obj.length ? `\n${this._indent}]` : ']';
60
+ } else {
61
+ yield '{';
62
+ this._indentLevel++;
63
+ let isFirst = true;
64
+ const entries = Object.entries(obj);
65
+
66
+ for (const [itemKey, itemValue] of entries) {
67
+ if (itemValue === undefined) {
68
+ continue;
69
+ }
70
+
71
+ yield `${isFirst ? '' : ','}\n${this._indent}${JSON.stringify(itemKey)}: `;
72
+ yield* this._stringify(itemValue);
73
+ isFirst = false;
74
+ }
75
+
76
+ this._indentLevel--;
77
+ yield entries.length ? `\n${this._indent}}` : '}';
78
+ }
79
+ }
80
+
81
+ }
82
+
83
+ exports.StatsSerializeStream = StatsSerializeStream;
84
+ exports.writeStats = writeStats;
85
+
86
+ async function writeStats(stats, filepath) {
87
+ return new Promise((resolve, reject) => {
88
+ new StatsSerializeStream(stats).on('end', resolve).on('error', reject).pipe(createWriteStream(filepath));
89
+ });
90
+ }
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+
3
+ /* eslint-disable max-len */
4
+ const path = require('path');
5
+
6
+ const fs = require('fs');
7
+
8
+ const _ = require('lodash');
9
+
10
+ const projectRoot = path.resolve(__dirname, '..');
11
+ const assetsRoot = path.join(projectRoot, 'public');
12
+ exports.renderViewer = renderViewer;
13
+ /**
14
+ * Escapes `<` characters in JSON to safely use it in `<script>` tag.
15
+ */
16
+
17
+ function escapeJson(json) {
18
+ return JSON.stringify(json).replace(/</gu, '\\u003c');
19
+ }
20
+
21
+ function getAssetContent(filename) {
22
+ const assetPath = path.join(assetsRoot, filename);
23
+
24
+ if (!assetPath.startsWith(assetsRoot)) {
25
+ throw new Error(`"${filename}" is outside of the assets root`);
26
+ }
27
+
28
+ return fs.readFileSync(assetPath, 'utf8');
29
+ }
30
+
31
+ function html(strings, ...values) {
32
+ return strings.map((string, index) => `${string}${values[index] || ''}`).join('');
33
+ }
34
+
35
+ function getScript(filename, mode) {
36
+ if (mode === 'static') {
37
+ return `<!-- ${_.escape(filename)} -->
38
+ <script>${getAssetContent(filename)}</script>`;
39
+ } else {
40
+ return `<script src="${_.escape(filename)}"></script>`;
41
+ }
42
+ }
43
+
44
+ function renderViewer({
45
+ title,
46
+ enableWebSocket,
47
+ chartData,
48
+ defaultSizes,
49
+ mode
50
+ } = {}) {
51
+ return html`<!DOCTYPE html>
52
+ <html>
53
+ <head>
54
+ <meta charset="UTF-8"/>
55
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
56
+ <title>${_.escape(title)}</title>
57
+ <link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABrVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+O1foceMD///+J0/qK1Pr7/v8Xdr/9///W8P4UdL7L7P0Scr2r4Pyj3vwad8D5/f/2/f+55f3E6f34+/2H0/ojfMKpzOd0rNgQcb3F3O/j9f7c8v6g3Pz0/P/w+v/q+P7n9v6T1/uQ1vuE0vqLut/y+v+Z2fvt+f+15Pzv9fuc2/vR7v2V2Pvd6/bg9P7I6/285/2y4/yp3/zp8vk8i8kqgMT7/P31+fyv4vxGkcz6/P6/6P3j7vfS5PNnpNUxhcbO7f7F6v3O4vHK3/DA2u631Ouy0eqXweKJud5wqthfoNMMbLvY8f73+v2dxeR8sNtTmdDx9/zX6PSjyeaCtd1YnNGX2PuQveCGt95Nls42h8dLlM3F4vBtAAAAM3RSTlMAAyOx0/sKBvik8opWGBMOAe3l1snDm2E9LSb06eHcu5JpHbarfHZCN9CBb08zzkdNS0kYaptYAAAFV0lEQVRYw92X51/aYBDHHS2O2qqttVbrqNq9m+TJIAYIShBkWwqIiCgoWvfeq7Z2/s29hyQNyUcR7LveGwVyXy6XH8/9rqxglLfUPLxVduUor3h0rfp2TYvpivk37929TkG037hffoX0+peVtZQc1589rigVUdXS/ABSAyEmGIO/1XfvldSK8vs3OqB6u3m0nxmIrvgB0dj7rr7Y9IbuF68hnfFaiHA/sxqm0wciIG43P60qKv9WXWc1RXGh/mFESFABTSBi0sNAKzqet17eCtOb3kZIDwxEEU0oAIJGYxNBDhBND29e0rtXXbcpuPmED9IhEAAQ/AXEaF8EPmnrrKsv0LvWR3fg5sWDNAFZOgAgaKvZDogHNU9MFwnnYROkc56RD5CjAbQX9Ow4g7upCsvYu55aSI/Nj0H1akgKQEUM94dwK65hYRmFU9MIcH/fqJYOZYcnuJSU/waKDgTOEVaVKhwrTRP5XzgSpAITYzom7UvkhFX5VutmxeNnWDjjswTKTyfgluNDGbUpWissXhF3s7mlSml+czWkg3D0l1nNjGNjz3myOQOa1KM/jOS6ebdbAVTCi4gljHSFrviza7tOgRWcS0MOUX9zdNgag5w7rRqA44Lzw0hr1WqES36dFliSJFlh2rXIae3FFcDDgKdxrUIDePr8jGcSClV1u7A9xeN0ModY/pHMxmR1EzRh8TJiwqsHmKW0l4FCEZI+jHio+JdPPE9qwQtTRxku2D8sIeRL2LnxWSllANCQGOIiqVHAz2ye2JR0DcH+HoxDkaADLjgxjKQ+AwCX/g0+DNgdG0ukYCONAe+dbc2IAc6fwt1ARoDSezNHxV2Cmzwv3O6lDMV55edBGwGK9n1+x2F8EDfAGCxug8MhpsMEcTEAWf3rx2vZhe/LAmtIn/6apE6PN0ULKgywD9mmdxbmFl3OvD5AS5fW5zLbv/YHmcsBTjf/afDz3MaZTVCfAP9z6/Bw6ycv8EUBWJIn9zYcoAWWlW9+OzO3vkTy8H+RANLmdrpOuYWdZYEXpo+TlCJrW5EARb7fF+bWdqf3hhyZI1nWJQHgznErZhbjoEsWqi8dQNoE294aldzFurwSABL2XXMf9+H1VQGke9exw5P/AnA5Pv5ngMul7LOvO922iwACu8WkCwLCafvM4CeWPxfA8lNHcWZSoi8EwMAIciKX2Z4SWCMAa3snCZ/G4EA8D6CMLNFsGQhkkz/gQNEBbPCbWsxGUpYVu3z8IyNAknwJkfPMEhLyrdi5RTyUVACkw4GSFRNWJNEW+fgPGwHD8/JxnRuLabN4CGNRkAE23na2+VmEAUmrYymSGjMAYqH84YUIyzgzs3XC7gNgH36Vcc4zKY9o9fgPBXUAiHHwVboBHGLiX6Zcjp1f2wu4tvzZKo0ecPnDtQYDQvJXaBeNzce45Fp28ZQLrEZVuFqgBwOalArKXnW1UzlnSusQKJqKYNuz4tOnI6sZG4zanpemv+7ySU2jbA9h6uhcgpfy6G2PahirDZ6zvq6zDduMVFTKvzw8wgyEdelwY9in3XkEPs3osJuwRQ4qTkfzifndg9Gfc4pdsu82+tTnHZTBa2EAMrqr2t43pguc8tNm7JQVQ2S0ukj2d22dhXYP0/veWtwKrCkNoNimAN5+Xr/oLrxswKbVJjteWrX7eR63o4j9q0GxnaBdWgGA5VStpanIjQmEhV0/nVt5VOFUvix6awJhPcAaTEShgrG+iGyvb5a0Ndb1YGHFPEwoqAinoaykaID1o1pdPNu7XsnCKQ3R+hwWIIhGvORcJUBYXe3Xa3vq/mF/N9V13ugufMkfXn+KHsRD0B8AAAAASUVORK5CYII=" type="image/x-icon" />
58
+
59
+ <script>
60
+ window.enableWebSocket = ${escapeJson(enableWebSocket)};
61
+ </script>
62
+ ${getScript('viewer.js', mode)}
63
+ </head>
64
+
65
+ <body>
66
+ <div id="app"></div>
67
+ <script>
68
+ window.chartData = ${escapeJson(chartData)};
69
+ window.defaultSizes = ${escapeJson(defaultSizes)};
70
+ </script>
71
+ </body>
72
+ </html>`;
73
+ }
@@ -69,8 +69,7 @@ class BaseFolder extends _Node.default {
69
69
 
70
70
  walk(walker, state = {}, deep = true) {
71
71
  let stopped = false;
72
-
73
- _lodash.default.each(this.children, child => {
72
+ Object.values(this.children).forEach(child => {
74
73
  if (deep && child.walk) {
75
74
  state = child.walk(walker, state, stop);
76
75
  } else {
@@ -79,7 +78,6 @@ class BaseFolder extends _Node.default {
79
78
 
80
79
  if (stopped) return false;
81
80
  });
82
-
83
81
  return state;
84
82
 
85
83
  function stop(finalState) {
@@ -26,7 +26,7 @@ class ConcatenatedModule extends _Module.default {
26
26
  }
27
27
 
28
28
  fillContentModules() {
29
- _lodash.default.each(this.data.modules, moduleData => this.addContentModule(moduleData));
29
+ this.data.modules.forEach(moduleData => this.addContentModule(moduleData));
30
30
  }
31
31
 
32
32
  addContentModule(moduleData) {
@@ -38,8 +38,7 @@ class ConcatenatedModule extends _Module.default {
38
38
 
39
39
  const [folders, fileName] = [pathParts.slice(0, -1), _lodash.default.last(pathParts)];
40
40
  let currentFolder = this;
41
-
42
- _lodash.default.each(folders, folderName => {
41
+ folders.forEach(folderName => {
43
42
  let childFolder = currentFolder.getChild(folderName);
44
43
 
45
44
  if (!childFolder) {
@@ -48,7 +47,6 @@ class ConcatenatedModule extends _Module.default {
48
47
 
49
48
  currentFolder = childFolder;
50
49
  });
51
-
52
50
  const module = new _ContentModule.default(fileName, moduleData, this);
53
51
  currentFolder.addChildModule(module);
54
52
  }
@@ -41,8 +41,7 @@ class Folder extends _BaseFolder.default {
41
41
 
42
42
  const [folders, fileName] = [pathParts.slice(0, -1), _lodash.default.last(pathParts)];
43
43
  let currentFolder = this;
44
-
45
- _lodash.default.each(folders, folderName => {
44
+ folders.forEach(folderName => {
46
45
  let childNode = currentFolder.getChild(folderName);
47
46
 
48
47
  if ( // Folder is not created yet
@@ -56,7 +55,6 @@ class Folder extends _BaseFolder.default {
56
55
 
57
56
  currentFolder = childNode;
58
57
  });
59
-
60
58
  const ModuleConstructor = moduleData.modules ? _ConcatenatedModule.default : _Module.default;
61
59
  const module = new ModuleConstructor(fileName, moduleData, this);
62
60
  currentFolder.addChildModule(module);
package/lib/utils.js CHANGED
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
 
3
3
  const {
4
- inspect
4
+ inspect,
5
+ types
5
6
  } = require('util');
6
7
 
7
8
  const _ = require('lodash');
@@ -17,11 +18,11 @@ function createAssetsFilter(excludePatterns) {
17
18
  pattern = new RegExp(pattern, 'u');
18
19
  }
19
20
 
20
- if (_.isRegExp(pattern)) {
21
+ if (types.isRegExp(pattern)) {
21
22
  return asset => pattern.test(asset);
22
23
  }
23
24
 
24
- if (!_.isFunction(pattern)) {
25
+ if (typeof pattern !== 'function') {
25
26
  throw new TypeError(`Pattern should be either string, RegExp or a function, but "${inspect(pattern, {
26
27
  depth: 0
27
28
  })}" got.`);
@@ -31,7 +32,7 @@ function createAssetsFilter(excludePatterns) {
31
32
  }).value();
32
33
 
33
34
  if (excludeFunctions.length) {
34
- return asset => _.every(excludeFunctions, fn => fn(asset) !== true);
35
+ return asset => excludeFunctions.every(fn => fn(asset) !== true);
35
36
  } else {
36
37
  return () => true;
37
38
  }