-
Notifications
You must be signed in to change notification settings - Fork 303
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[WALL-3660] feature/switch to total size (#15483)
* feat: improved bundle analysis * feat: removed unnecessary table * feat: added a bit of tolerance for orange, so it will not trigger orange for too minuscule changes
- Loading branch information
1 parent
630659b
commit dc78fdc
Showing
2 changed files
with
161 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,122 +1,170 @@ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
|
||
function roundUpToDecimals(num, decimals) { | ||
const factor = Math.pow(10, decimals); | ||
return Math.ceil(num * factor) / factor; | ||
} | ||
|
||
function readJsonFile(filePath) { | ||
if (fs.existsSync(filePath)) { | ||
const data = fs.readFileSync(filePath, 'utf-8'); | ||
return JSON.parse(data); | ||
// read and use parameters from command line | ||
const args = process.argv.slice(2); // Skip the first two elements | ||
let format = args.find(arg => arg.startsWith('--format='))?.split('=')[1] || 'html'; | ||
let orangeThreshold = +(args.find(arg => arg.startsWith('--orangeThreshold='))?.split('=')[1] || 0.5); | ||
let redThreshold = +(args.find(arg => arg.startsWith('--redThreshold='))?.split('=')[1] || 5); | ||
|
||
// main function execution | ||
main(); | ||
|
||
function main() { | ||
// format: [package]: { oldSize, newSize, diff, percentage } | ||
const sizes = analyse(); | ||
|
||
// format to different output based on the format parameter | ||
// nice table in html if its for comment, nice table in console if its for console, or just true/false if its just to check validity | ||
if (format === 'html') { | ||
let formattedOutput = formatToTable(sizes); | ||
console.log(formattedOutput); | ||
} else if (format === 'console') { | ||
let formattedOutput = formatToConsole(sizes); | ||
console.table(formattedOutput, ['oldSize', 'newSize', 'diff', 'percentage', 'alert']); | ||
} else if (format === 'boolean') { | ||
const aboveRedThreshold = Object.values(sizes).some(pkg => pkg.percentage > redThreshold); | ||
if (aboveRedThreshold) { | ||
console.log('true'); | ||
} else { | ||
console.log('false'); | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
function calculateDiff(oldSize, newSize) { | ||
return newSize - oldSize; | ||
} | ||
function analyse() { | ||
const packagesDir = './packages'; | ||
const oldPackagesDir = './old/packages'; | ||
|
||
function calculatePercentage(oldSize, newSize) { | ||
if (oldSize === 0) { | ||
return newSize === 0 ? 0 : 100; | ||
} | ||
return ((newSize - oldSize) / oldSize) * 100; | ||
} | ||
const packages = [...new Set([...fs.readdirSync(packagesDir), ...fs.readdirSync(oldPackagesDir)])]; | ||
|
||
function formatSize(size, roundUp) { | ||
if (size === null) { | ||
return '-'; | ||
} | ||
const result = {}; | ||
|
||
const formattedSize = roundUp ? roundUpToDecimals(size / 1024, 2) + 'kb' : (size / 1024).toFixed(2) + 'kb'; | ||
return formattedSize; | ||
} | ||
for (const pkg of packages) { | ||
const oldReport = readJsonFile(path.join(oldPackagesDir, pkg, 'report.json')); | ||
const newReport = readJsonFile(path.join(packagesDir, pkg, 'report.json')); | ||
|
||
if (!newReport) { | ||
continue; | ||
} | ||
|
||
const packagesDir = './packages'; | ||
const oldPackagesDir = './old/packages'; | ||
const packages = [...new Set([...fs.readdirSync(packagesDir), ...fs.readdirSync(oldPackagesDir)])]; | ||
const oldSize = oldReport ? oldReport.reduce((acc, item) => acc + item.gzipSize, 0) : null; | ||
const newSize = newReport ? newReport.reduce((acc, item) => acc + item.gzipSize, 0) : null; | ||
|
||
let tableRows = ''; | ||
let diff = oldSize && newSize ? newSize - oldSize : oldSize || newSize; | ||
let percentage = oldSize && newSize ? calculatePercentage(oldSize, newSize) : null; | ||
|
||
for (const pkg of packages) { | ||
const oldReport = readJsonFile(path.join(oldPackagesDir, pkg, 'report.json')); | ||
const newReport = readJsonFile(path.join(packagesDir, pkg, 'report.json')); | ||
result[pkg] = { | ||
oldSize, | ||
newSize, | ||
diff, | ||
percentage, | ||
}; | ||
} | ||
|
||
const oldSize = oldReport ? oldReport[0].gzipSize : null; | ||
const newSize = newReport ? newReport[0].gzipSize : null; | ||
let diff = oldSize && newSize ? calculateDiff(oldSize, newSize) : null; | ||
return result; | ||
} | ||
|
||
if (oldSize === null) { | ||
diff = newSize; | ||
function formatToTable(sizes) { | ||
const GREEN_SIGN = '🟢'; | ||
const YELLOW_SIGN = '🟡'; | ||
const RED_SIGN = '🔴'; | ||
|
||
let tableRows = ''; | ||
for (const [pkg, { oldSize, newSize, diff, percentage }] of Object.entries(sizes)) { | ||
const formattedPercentage = formatPercentageWithSign(percentage); | ||
const lightSign = | ||
percentage > redThreshold ? RED_SIGN : percentage > orangeThreshold ? YELLOW_SIGN : GREEN_SIGN; | ||
|
||
tableRows += ` | ||
<tr> | ||
<td>${pkg}</td> | ||
<td>${formatBytes(oldSize)}</td> | ||
<td>${formatBytes(newSize)}</td> | ||
<td>${formatBytes(diff, true)}</td> | ||
<td>${formattedPercentage} ${lightSign}</td> | ||
</tr> | ||
`.trim(); | ||
} | ||
|
||
if (newSize === null) { | ||
diff = oldSize; | ||
return ` | ||
<table> | ||
<thead> | ||
<th>package</th> | ||
<th>old</th> | ||
<th>new</th> | ||
<th>diff</th> | ||
<th>pct change</th> | ||
</thead> | ||
<tbody> | ||
${tableRows} | ||
</tbody> | ||
</table>` | ||
.replace(/[\n\t]/g, '') | ||
.trim(); | ||
} | ||
|
||
function formatToConsole(sizes) { | ||
Object.keys(sizes).forEach(key => { | ||
const pkg = sizes[key]; | ||
pkg.oldSize = formatBytes(pkg.oldSize); | ||
pkg.newSize = formatBytes(pkg.newSize); | ||
pkg.diff = formatBytes(pkg.diff, true); | ||
pkg.alert = pkg.percentage > redThreshold ? 'FAIL' : pkg.percentage > orangeThreshold ? 'WARN' : 'OK'; | ||
pkg.percentage = formatPercentageWithSign(pkg.percentage); | ||
}); | ||
return sizes; | ||
} | ||
|
||
function readJsonFile(filePath) { | ||
if (fs.existsSync(filePath)) { | ||
const data = fs.readFileSync(filePath, 'utf-8'); | ||
return JSON.parse(data); | ||
} | ||
return null; | ||
} | ||
|
||
let diffText = '-'; | ||
function calculatePercentage(oldSize, newSize) { | ||
return ((newSize - oldSize) / oldSize) * 100; | ||
} | ||
|
||
if (diff !== 0) { | ||
diffText = diff < 0 ? '-' : '+' + formatSize(diff, true); | ||
} else { | ||
diffText = '+0kb'; | ||
function formatBytes(bytes, sign = false) { | ||
if (bytes === null || isNaN(bytes)) { | ||
return 'n/a'; | ||
} | ||
|
||
let percentage = oldSize && newSize ? calculatePercentage(oldSize, newSize) : null; | ||
let formattedValue = ''; | ||
|
||
if (oldSize === null) { | ||
percentage = 100; | ||
if (bytes < 1024) { | ||
formattedValue = bytes + ' B'; // Bytes | ||
} else if (bytes < 1048576) { | ||
formattedValue = Math.round(bytes / 1024) + ' KB'; // Kilobytes | ||
} else { | ||
formattedValue = (bytes / 1048576).toFixed(1) + ' MB'; // Megabytes | ||
} | ||
|
||
if (newSize === null) { | ||
percentage = -100; | ||
if (sign) { | ||
if (bytes === 0) { | ||
return '0 B'; | ||
} | ||
formattedValue = bytes >= 0 ? '+' + formattedValue : '-' + formattedValue; | ||
} | ||
|
||
let percentageText = '-'; | ||
let percentageEmoji; | ||
return formattedValue; | ||
} | ||
|
||
if (percentage === 0) { | ||
percentageEmoji = ''; | ||
} else if (percentage < 0) { | ||
percentageEmoji = '🟢'; // green for decrease | ||
} else if (percentage >= 0 && percentage <= 5) { | ||
percentageEmoji = '🟡'; // yellow for small increase | ||
} else { | ||
percentageEmoji = '🔴'; // red for larger increase | ||
function formatPercentageWithSign(percentage) { | ||
if (percentage === null || isNaN(percentage)) { | ||
return 'n/a'; | ||
} | ||
|
||
if (percentage !== 0) { | ||
percentageText = percentage.toFixed(2) + '%'; | ||
} else { | ||
percentageText = '0%'; | ||
const absPercentage = Math.abs(percentage); | ||
const decimalPoints = absPercentage < 10 ? 1 : 2; | ||
let formattedValue = percentage.toFixed(decimalPoints) + '%'; | ||
|
||
if (percentage === 0) { | ||
return '0%'; | ||
} | ||
|
||
tableRows += ` | ||
<tr> | ||
<td>${pkg}</td> | ||
<td>${formatSize(oldSize)}</td> | ||
<td>${formatSize(newSize)}</td> | ||
<td>${diffText}</td> | ||
<td>${percentageText} ${percentageEmoji}</td> | ||
</tr> | ||
`.trim(); | ||
return percentage >= 0 ? '+' + formattedValue : '−' + formattedValue; | ||
} | ||
|
||
console.log( | ||
` | ||
<table> | ||
<thead> | ||
<th>package</th> | ||
<th>old</th> | ||
<th>new</th> | ||
<th>diff</th> | ||
<th>percentage</th> | ||
</thead> | ||
<tbody> | ||
${tableRows} | ||
</tbody> | ||
</table> | ||
`.trim() | ||
); |