/
stats.js
130 lines (116 loc) · 3.45 KB
/
stats.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
'use strict';
const Table = require('cli-table');
const filesize = require('filesize');
const chalk = require('chalk');
const join = require('path').join;
const fs = require('fs');
const mkdirp = require('mkdirp');
const BUNDLE_SIZES_FILE_NAME = join(__dirname, '../../build/bundle-sizes.json');
const prevBuildResults = fs.existsSync(BUNDLE_SIZES_FILE_NAME)
? require(BUNDLE_SIZES_FILE_NAME)
: {bundleSizes: []};
const currentBuildResults = {
// Mutated inside build.js during a build run.
bundleSizes: [],
};
function saveResults() {
if (process.env.CIRCLE_NODE_TOTAL) {
// In CI, write the bundle sizes to a subdirectory and append the node index
// to the filename. A downstream job will consolidate these into a
// single file.
const nodeIndex = process.env.CIRCLE_NODE_INDEX;
mkdirp.sync('build/sizes');
fs.writeFileSync(
join('build', 'sizes', `bundle-sizes-${nodeIndex}.json`),
JSON.stringify(currentBuildResults, null, 2)
);
} else {
// Write all the bundle sizes to a single JSON file.
fs.writeFileSync(
BUNDLE_SIZES_FILE_NAME,
JSON.stringify(currentBuildResults, null, 2)
);
}
}
function fractionalChange(prev, current) {
return (current - prev) / prev;
}
function percentChangeString(change) {
if (!isFinite(change)) {
// When a new package is created
return 'n/a';
}
const formatted = (change * 100).toFixed(1);
if (/^-|^0(?:\.0+)$/.test(formatted)) {
return `${formatted}%`;
} else {
return `+${formatted}%`;
}
}
const resultsHeaders = [
'Bundle',
'Prev Size',
'Current Size',
'Diff',
'Prev Gzip',
'Current Gzip',
'Diff',
];
function generateResultsArray(current, prevResults) {
return current.bundleSizes
.map(result => {
const prev = prevResults.bundleSizes.filter(
res =>
res.filename === result.filename &&
res.bundleType === result.bundleType
)[0];
if (result === prev) {
// We didn't rebuild this bundle.
return;
}
const size = result.size;
const gzip = result.gzip;
let prevSize = prev ? prev.size : 0;
let prevGzip = prev ? prev.gzip : 0;
return {
filename: result.filename,
bundleType: result.bundleType,
packageName: result.packageName,
prevSize: filesize(prevSize),
prevFileSize: filesize(size),
prevFileSizeChange: fractionalChange(prevSize, size),
prevFileSizeAbsoluteChange: size - prevSize,
prevGzip: filesize(prevGzip),
prevGzipSize: filesize(gzip),
prevGzipSizeChange: fractionalChange(prevGzip, gzip),
prevGzipSizeAbsoluteChange: gzip - prevGzip,
};
// Strip any nulls
})
.filter(f => f);
}
function printResults() {
const table = new Table({
head: resultsHeaders.map(label => chalk.gray.yellow(label)),
});
const results = generateResultsArray(currentBuildResults, prevBuildResults);
results.forEach(result => {
table.push([
chalk.white.bold(`${result.filename} (${result.bundleType})`),
chalk.gray.bold(result.prevSize),
chalk.white.bold(result.prevFileSize),
percentChangeString(result.prevFileSizeChange),
chalk.gray.bold(result.prevGzip),
chalk.white.bold(result.prevGzipSize),
percentChangeString(result.prevGzipSizeChange),
]);
});
return table.toString();
}
module.exports = {
currentBuildResults,
generateResultsArray,
printResults,
saveResults,
resultsHeaders,
};