UNPKG

5.03 kBJavaScriptView Raw
1'use strict';
2
3var fs = require('fs');
4var path = require('path');
5
6var _ = require('lodash');
7var gzipSize = require('gzip-size');
8
9var Logger = require('./Logger');
10
11var _require = require('../lib/tree'),
12 Folder = _require.Folder;
13
14var _require2 = require('../lib/parseUtils'),
15 parseBundle = _require2.parseBundle;
16
17var FILENAME_QUERY_REGEXP = /\?.*$/;
18var MULTI_MODULE_REGEXP = /^multi /;
19
20module.exports = {
21 getViewerData,
22 readStatsFromFile
23};
24
25function getViewerData(bundleStats, bundleDir, opts) {
26 var _ref = opts || {},
27 _ref$logger = _ref.logger,
28 logger = _ref$logger === undefined ? new Logger() : _ref$logger;
29
30 // Sometimes all the information is located in `children` array (e.g. problem in #10)
31
32
33 if (_.isEmpty(bundleStats.assets) && !_.isEmpty(bundleStats.children)) {
34 bundleStats = bundleStats.children[0];
35 }
36
37 // Picking only `*.js` assets from bundle that has non-empty `chunks` array
38 bundleStats.assets = _.filter(bundleStats.assets, function (asset) {
39 // Removing query part from filename (yes, somebody uses it for some reason and Webpack supports it)
40 // See #22
41 asset.name = asset.name.replace(FILENAME_QUERY_REGEXP, '');
42
43 return _.endsWith(asset.name, '.js') && !_.isEmpty(asset.chunks);
44 });
45
46 // Trying to parse bundle assets and get real module sizes if `bundleDir` is provided
47 var bundlesSources = null;
48 var parsedModules = null;
49
50 if (bundleDir) {
51 bundlesSources = {};
52 parsedModules = {};
53
54 var _iteratorNormalCompletion = true;
55 var _didIteratorError = false;
56 var _iteratorError = undefined;
57
58 try {
59 for (var _iterator = bundleStats.assets[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
60 var statAsset = _step.value;
61
62 var assetFile = path.join(bundleDir, statAsset.name);
63 var bundleInfo = void 0;
64
65 try {
66 bundleInfo = parseBundle(assetFile);
67 } catch (err) {
68 bundleInfo = null;
69 }
70
71 if (!bundleInfo) {
72 logger.warn(`\nCouldn't parse bundle asset "${assetFile}".\n` + 'Analyzer will use module sizes from stats file.\n');
73 parsedModules = null;
74 bundlesSources = null;
75 break;
76 }
77
78 bundlesSources[statAsset.name] = bundleInfo.src;
79 _.assign(parsedModules, bundleInfo.modules);
80 }
81 } catch (err) {
82 _didIteratorError = true;
83 _iteratorError = err;
84 } finally {
85 try {
86 if (!_iteratorNormalCompletion && _iterator.return) {
87 _iterator.return();
88 }
89 } finally {
90 if (_didIteratorError) {
91 throw _iteratorError;
92 }
93 }
94 }
95 }
96
97 var assets = _.transform(bundleStats.assets, function (result, statAsset) {
98 var asset = result[statAsset.name] = _.pick(statAsset, 'size');
99
100 if (bundlesSources) {
101 asset.parsedSize = bundlesSources[statAsset.name].length;
102 asset.gzipSize = gzipSize.sync(bundlesSources[statAsset.name]);
103 }
104
105 // Picking modules from current bundle script
106 asset.modules = _(bundleStats.modules).filter(function (statModule) {
107 return assetHasModule(statAsset, statModule);
108 }).each(function (statModule) {
109 if (parsedModules) {
110 statModule.parsedSrc = parsedModules[statModule.id];
111 }
112 });
113
114 asset.tree = createModulesTree(asset.modules);
115 }, {});
116
117 return _.transform(assets, function (result, asset, filename) {
118 result.push({
119 label: filename,
120 // Not using `asset.size` here provided by Webpack because it can be very confusing when `UglifyJsPlugin` is used.
121 // In this case all module sizes from stats file will represent unminified module sizes, but `asset.size` will
122 // be the size of minified bundle.
123 statSize: asset.tree.size,
124 parsedSize: asset.parsedSize,
125 gzipSize: asset.gzipSize,
126 groups: _.invokeMap(asset.tree.children, 'toChartData')
127 });
128 }, []);
129}
130
131function readStatsFromFile(filename) {
132 return JSON.parse(fs.readFileSync(filename, 'utf8'));
133}
134
135function assetHasModule(statAsset, statModule) {
136 return _.some(statModule.chunks, function (moduleChunk) {
137 return _.includes(statAsset.chunks, moduleChunk);
138 });
139}
140
141function createModulesTree(modules) {
142 var root = new Folder('.');
143
144 _.each(modules, function (module) {
145 var path = getModulePath(module);
146
147 if (path) {
148 root.addModuleByPath(path, module);
149 }
150 });
151
152 return root;
153}
154
155function getModulePath(module) {
156 if (MULTI_MODULE_REGEXP.test(module.identifier)) {
157 return [module.identifier];
158 }
159
160 var parsedPath = _
161 // Removing loaders from module path: they're joined by `!` and the last part is a raw module path
162 .last(module.name.split('!'))
163 // Splitting module path into parts
164 .split('/')
165 // Removing first `.`
166 .slice(1)
167 // Replacing `~` with `node_modules`
168 .map(function (part) {
169 return part === '~' ? 'node_modules' : part;
170 });
171
172 return parsedPath.length ? parsedPath : null;
173}
\No newline at end of file