UNPKG

6.35 kBJavaScriptView Raw
1'use strict';
2var __importDefault =
3 (this && this.__importDefault) ||
4 function (mod) {
5 return mod && mod.__esModule ? mod : { default: mod };
6 };
7Object.defineProperty(exports, '__esModule', { value: true });
8exports.getWebTreeMapData = exports.makeMergedTreeDataMap = exports.generateHtml = void 0;
9const btoa_1 = __importDefault(require('btoa'));
10const ejs_1 = __importDefault(require('ejs'));
11const fs_1 = __importDefault(require('fs'));
12const path_1 = __importDefault(require('path'));
13const escape_html_1 = __importDefault(require('escape-html'));
14const lodash_1 = require('lodash');
15const helpers_1 = require('./helpers');
16const coverage_1 = require('./coverage');
17const COMBINED_BUNDLE_NAME = '[combined]';
18function getTreeDataMap(exploreResults) {
19 let treeData = exploreResults.map((data) => ({
20 name: data.bundleName,
21 data: getWebTreeMapData(data.files),
22 }));
23 if (treeData.length > 1) {
24 treeData = [makeMergedTreeDataMap(lodash_1.cloneDeep(treeData)), ...treeData];
25 }
26 for (const webTreeData of treeData) {
27 addSizeToTitle(webTreeData.data, webTreeData.data.data['$area']);
28 }
29 return { ...treeData };
30}
31function generateHtml(exploreResults, options) {
32 const assets = {
33 webtreemapJs: btoa_1.default(
34 fs_1.default.readFileSync(require.resolve('./vendor/webtreemap.js'))
35 ),
36 webtreemapCss: btoa_1.default(
37 fs_1.default.readFileSync(require.resolve('./vendor/webtreemap.css'))
38 ),
39 };
40 const treeDataMap = getTreeDataMap(exploreResults);
41 const bundles = exploreResults.map((data) => ({
42 name: data.bundleName,
43 size: helpers_1.formatBytes(data.totalBytes),
44 }));
45 if (exploreResults.length > 1) {
46 bundles.unshift({
47 name: COMBINED_BUNDLE_NAME,
48 size: helpers_1.formatBytes(
49 exploreResults.reduce((total, result) => total + result.totalBytes, 0)
50 ),
51 });
52 }
53 const template = helpers_1.getFileContent(path_1.default.join(__dirname, 'tree-viz.ejs'));
54 return ejs_1.default.render(template, {
55 options,
56 bundles,
57 treeDataMap,
58 webtreemapJs: assets.webtreemapJs,
59 webtreemapCss: assets.webtreemapCss,
60 });
61}
62exports.generateHtml = generateHtml;
63function makeMergedTreeDataMap(treeData) {
64 const data = newNode('/');
65 data.children = [];
66 for (const result of treeData) {
67 const childTree = result.data;
68 childTree.name = result.name;
69 data.data['$area'] += childTree.data['$area'];
70 data.children.push(childTree);
71 }
72 const commonPrefix = helpers_1.getCommonPathPrefix(data.children.map((node) => node.name));
73 const commonPrefixLength = commonPrefix.length;
74 if (commonPrefixLength > 0) {
75 for (const node of data.children) {
76 node.name = node.name.slice(commonPrefixLength);
77 }
78 }
79 return {
80 name: COMBINED_BUNDLE_NAME,
81 data,
82 };
83}
84exports.makeMergedTreeDataMap = makeMergedTreeDataMap;
85function getNodePath(parts, depthIndex) {
86 return parts.slice(0, depthIndex + 1).join('/');
87}
88const WEBPACK_FILENAME_PREFIX = 'webpack:///';
89const WEBPACK_FILENAME_PREFIX_LENGTH = WEBPACK_FILENAME_PREFIX.length;
90const PATH_SEPARATOR_REGEX = /[\\/]/;
91function splitFilename(file) {
92 const webpackPrefixIndex = file.indexOf(WEBPACK_FILENAME_PREFIX);
93 if (webpackPrefixIndex !== -1) {
94 return [
95 ...file.substring(0, webpackPrefixIndex).split('/'),
96 WEBPACK_FILENAME_PREFIX,
97 ...file.substring(webpackPrefixIndex + WEBPACK_FILENAME_PREFIX_LENGTH).split('/'),
98 ].filter(Boolean);
99 }
100 return file.split(PATH_SEPARATOR_REGEX);
101}
102function getTreeNodesMap(fileDataMap) {
103 let partsSourceTuples = Object.keys(fileDataMap).map((file) => [splitFilename(file), file]);
104 const maxDepth = Math.max(...partsSourceTuples.map(([parts]) => parts.length));
105 for (let depthIndex = 0; depthIndex < maxDepth; depthIndex += 1) {
106 partsSourceTuples = partsSourceTuples.map(([parts, file], currentNodeIndex) => {
107 if (parts[depthIndex]) {
108 const nodePath = getNodePath(parts, depthIndex);
109 const hasSameRootPaths = partsSourceTuples.some(([pathParts], index) => {
110 if (index === currentNodeIndex) {
111 return false;
112 }
113 if (!pathParts[depthIndex]) {
114 return false;
115 }
116 return getNodePath(pathParts, depthIndex) === nodePath;
117 });
118 if (!hasSameRootPaths) {
119 return [[...parts.slice(0, depthIndex), parts.slice(depthIndex).join('/')], file];
120 }
121 }
122 return [parts, file];
123 });
124 }
125 return partsSourceTuples.reduce((result, [parts, file]) => {
126 result[file] = parts;
127 return result;
128 }, {});
129}
130function getWebTreeMapData(files) {
131 const treeNodesMap = getTreeNodesMap(files);
132 const treeData = newNode('/');
133 for (const source in files) {
134 addNode(treeNodesMap[source], files[source], treeData);
135 }
136 return treeData;
137}
138exports.getWebTreeMapData = getWebTreeMapData;
139function newNode(name) {
140 return {
141 name: escape_html_1.default(name),
142 data: {
143 $area: 0,
144 },
145 };
146}
147function setNodeData(node, fileData) {
148 const size = node.data['$area'] + fileData.size;
149 if (fileData.coveredSize !== undefined) {
150 const coveredSize = (node.data.coveredSize || 0) + fileData.coveredSize;
151 node.data.coveredSize = coveredSize;
152 node.data.backgroundColor = coverage_1.getColorByPercent(coveredSize / size);
153 }
154 node.data['$area'] = size;
155}
156function addNode(parts, fileData, treeData) {
157 if (fileData.size === 0) {
158 return;
159 }
160 let node = treeData;
161 setNodeData(node, fileData);
162 parts.forEach((part) => {
163 if (!node.children) {
164 node.children = [];
165 }
166 let child = node.children.find((child) => child.name === part);
167 if (!child) {
168 child = newNode(part);
169 node.children.push(child);
170 }
171 node = child;
172 setNodeData(child, fileData);
173 });
174}
175function addSizeToTitle(node, total) {
176 const { $area: size, coveredSize } = node.data;
177 const titleParts = [
178 node.name,
179 helpers_1.formatBytes(size),
180 `${helpers_1.formatPercent(size, total, 1)}%`,
181 ];
182 if (coveredSize !== undefined && node.children === undefined) {
183 titleParts.push(`Coverage: ${helpers_1.formatPercent(coveredSize, size, 1)}%`);
184 }
185 node.name = titleParts.join(' • ');
186 if (node.children) {
187 node.children.forEach((child) => {
188 addSizeToTitle(child, total);
189 });
190 }
191}
192//# sourceMappingURL=html.js.map