Update frontend-js-size.yml

This commit is contained in:
syuilo 2026-06-20 19:58:49 +09:00
commit 36d78a788d

View file

@ -133,14 +133,6 @@ jobs:
return value.replace(/\.0+$/, '').replace(/(\.\d*?)0+$/, '$1'); return value.replace(/\.0+$/, '').replace(/(\.\d*?)0+$/, '$1');
} }
function formatPercent(diff, beforeSize) {
if (diff == null || beforeSize == null) return null;
if (diff === 0) return '0%';
if (beforeSize === 0) return null;
const sign = diff > 0 ? '+' : '-';
return `${sign}${Math.round(Math.abs(diff) / beforeSize * 100)}%`;
}
function formatMathText(text) { function formatMathText(text) {
return text return text
.replaceAll('\\', '\\\\') .replaceAll('\\', '\\\\')
@ -158,18 +150,13 @@ jobs:
return `$\\color{${color}}{\\text{${formatMathText(text)}}}$`; return `$\\color{${color}}{\\text{${formatMathText(text)}}}$`;
} }
function formatDiffPercent(beforeSize, diff) { function formatDiffPercent(beforeSize, afterSize) {
if (diff == null) return '-'; if (beforeSize == null || beforeSize === 0 || afterSize == null || afterSize === 0) return '-';
const percent = formatPercent(diff, beforeSize); const diff = afterSize - beforeSize;
if (diff === 0) return `${percent}`; if (diff === 0) return `0%`;
const text = `${percent}`; const percent = Math.round(diff / beforeSize * 100);
const color = diff > 0 ? 'orange' : 'green'; const color = diff > 0 ? 'orange' : 'green';
return `$\\color{${color}}{\\text{${formatMathText(text)}}}$`; return `$\\color{${color}}{\\text{${formatMathText(percent)}}}$`;
}
function sizeDiff(beforeSize, afterSize) {
if (beforeSize == null && afterSize == null) return null;
return (afterSize ?? 0) - (beforeSize ?? 0);
} }
function escapeCell(value) { function escapeCell(value) {
@ -291,34 +278,36 @@ jobs:
.filter((key) => after.chunks[key] == null); .filter((key) => after.chunks[key] == null);
} }
function compareRows(keys, before, after) { function getChunkComparisonRows(keys, before, after) {
return keys.map((key) => { return keys.map((key) => {
const beforeEntry = before.chunks[key]; const beforeEntry = before.chunks[key];
const afterEntry = after.chunks[key]; const afterEntry = after.chunks[key];
const beforeSize = beforeEntry?.size ?? null; const beforeSize = beforeEntry?.size ?? 0;
const afterSize = afterEntry?.size ?? null; const afterSize = afterEntry?.size ?? 0;
return { return {
key, key,
name: entryDisplayName(afterEntry ?? beforeEntry), name: entryDisplayName(beforeEntry ?? afterEntry),
chunkFile: beforeEntry?.file ?? afterEntry?.file,
beforeSize, beforeSize,
afterSize, afterSize,
diff: sizeDiff(beforeSize, afterSize), sortSize: Math.max(beforeSize, afterSize),
sortSize: Math.max(beforeSize ?? 0, afterSize ?? 0),
}; };
}); });
} }
function markdownTable(rows, emptyMessage = '_No JavaScript chunks found._') { function markdownTable(rows, total) {
if (rows.length === 0) { if (rows.length === 0) return '_No data_';
return emptyMessage;
}
const lines = [ const lines = [
'| Chunk | Before | After | Diff | Diff (%) |', '| Chunk | Before | After | Diff | Diff (%) |',
'| --- | ---: | ---: | ---: | ---: |', '| --- | ---: | ---: | ---: | ---: |',
]; ];
if (total != null) {
lines.push(`| (total) | ${formatBytes(total.beforeSize)} | ${formatBytes(total.afterSize)} | ${formatDiff(total.afterSize - total.beforeSize)} | ${formatDiffPercent(total.beforeSize, total.afterSize)} |`);
lines.push('| | | | | |');
}
for (const row of rows) { for (const row of rows) {
lines.push(`| \`${escapeCell(row.name)}\` | ${formatBytes(row.beforeSize)} | ${formatBytes(row.afterSize)} | ${formatDiff(row.diff)} | ${formatDiffPercent(row.beforeSize, row.diff)} |`); lines.push(`| <details><summary>\`${escapeCell(row.name)}\`</summary> \`${escapeCell(row.chunkFile)}\` </details> | ${formatBytes(row.beforeSize)} | ${formatBytes(row.afterSize)} | ${formatDiff(row.afterSize - row.beforeSize)} | ${formatDiffPercent(row.beforeSize, row.afterSize)} |`);
} }
return lines.join('\n'); return lines.join('\n');
} }
@ -329,48 +318,25 @@ jobs:
return { return {
key, key,
name: entryDisplayName(entry), name: entryDisplayName(entry),
chunkFile: entry.file,
size: entry.size, size: entry.size,
}; };
}); });
} }
function markdownChunkTable(rows, emptyMessage = '_No JavaScript chunks found._') { function markdownChunkTable(rows) {
if (rows.length === 0) { if (rows.length === 0) return '_No data_';
return emptyMessage;
}
const lines = [ const lines = [
'| Chunk | Size |', '| Chunk | Size |',
'| --- | ---: |', '| --- | ---: |',
]; ];
for (const row of rows) { for (const row of rows) {
lines.push(`| \`${escapeCell(row.name)}\` | ${formatBytes(row.size)} |`); lines.push(`| <details><summary>\`${escapeCell(row.name)}\`</summary> \`${escapeCell(row.chunkFile)}\` </details> | ${formatBytes(row.size)} |`);
} }
return lines.join('\n'); return lines.join('\n');
} }
function topKeys(keys, before, after) {
return compareRows(keys, before, after)
.sort((a, b) => b.sortSize - a.sortSize || a.name.localeCompare(b.name))
.slice(0, 30)
.map((row) => row.key);
}
function compareDiffRows(a, b) {
return Math.abs(b.diff ?? 0) - Math.abs(a.diff ?? 0)
|| (b.diff ?? 0) - (a.diff ?? 0)
|| b.sortSize - a.sortSize
|| a.name.localeCompare(b.name);
}
function diffKeys(keys, before, after) {
return compareRows(keys, before, after)
.filter((row) => row.diff !== 0 && row.diff != null)
.sort(compareDiffRows)
.slice(0, 30)
.map((row) => row.key);
}
const beforeDir = process.argv[2]; const beforeDir = process.argv[2];
const afterDir = process.argv[3]; const afterDir = process.argv[3];
const outFile = process.argv[4]; const outFile = process.argv[4];
@ -381,11 +347,20 @@ jobs:
const after = await collectReport(afterDir); const after = await collectReport(afterDir);
const commonChunkKeys = commonKeys(before, after); const commonChunkKeys = commonKeys(before, after);
const topRows = compareRows(topKeys(commonChunkKeys, before, after), before, after) const comparisonRows = getChunkComparisonRows(commonChunkKeys, before, after);
.sort((a, b) => b.sortSize - a.sortSize || a.name.localeCompare(b.name));
const diffRows = compareRows(diffKeys(commonChunkKeys, before, after), before, after) const diffRows = comparisonRows
.sort(compareDiffRows); .filter((row) => row.beforeSize !== row.afterSize)
.sort((a, b) => Math.abs(b.afterSize - b.beforeSize) - Math.abs(a.afterSize - a.beforeSize)
|| (b.afterSize - b.beforeSize) - (a.afterSize - a.beforeSize)
|| b.sortSize - a.sortSize
|| a.name.localeCompare(b.name))
.slice(0, 30);
const diffTotal = {
beforeSize: comparisonRows.reduce((sum, row) => sum + row.beforeSize, 0),
afterSize: comparisonRows.reduce((sum, row) => sum + row.afterSize, 0),
};
const addedRows = chunkRows(addedKeys(before, after), after) const addedRows = chunkRows(addedKeys(before, after), after)
.sort((a, b) => b.size - a.size || a.name.localeCompare(b.name)); .sort((a, b) => b.size - a.size || a.name.localeCompare(b.name));
@ -397,8 +372,17 @@ jobs:
...before.startupKeys, ...before.startupKeys,
...after.startupKeys, ...after.startupKeys,
]); ]);
const startupRows = compareRows([...startupKeys].filter((key) => before.chunks[key] != null && after.chunks[key] != null), before, after) const startupComparisonRows = getChunkComparisonRows([...startupKeys], before, after);
const startupRows = startupComparisonRows
.sort((a, b) => b.sortSize - a.sortSize || a.name.localeCompare(b.name)); .sort((a, b) => b.sortSize - a.sortSize || a.name.localeCompare(b.name));
const startupTotal = {
beforeSize: startupComparisonRows.reduce((sum, row) => sum + row.beforeSize, 0),
afterSize: startupComparisonRows.reduce((sum, row) => sum + row.afterSize, 0),
};
const largeRows = comparisonRows
.sort((a, b) => b.sortSize - a.sortSize || a.name.localeCompare(b.name))
.slice(0, 30);
const body = [ const body = [
marker, marker,
@ -407,28 +391,28 @@ jobs:
'<details open>', '<details open>',
`<summary>Diffs</summary>`, `<summary>Diffs</summary>`,
'', '',
markdownTable(diffRows, '_No chunk size changes found._'), markdownTable(diffRows, diffTotal),
'', '',
'</details>', '</details>',
'', '',
'<details>', '<details>',
`<summary>Added (${addedRows.length})</summary>`, `<summary>Added (${addedRows.length})</summary>`,
'', '',
markdownChunkTable(addedRows, '_No chunks added._'), markdownChunkTable(addedRows),
'', '',
'</details>', '</details>',
'', '',
'<details>', '<details>',
`<summary>Removed (${removedRows.length})</summary>`, `<summary>Removed (${removedRows.length})</summary>`,
'', '',
markdownChunkTable(removedRows, '_No chunks removed._'), markdownChunkTable(removedRows),
'', '',
'</details>', '</details>',
'', '',
'<details>', '<details>',
`<summary>Startup</summary>`, `<summary>Startup</summary>`,
'', '',
markdownTable(startupRows), markdownTable(startupRows, startupTotal),
'', '',
`_Only ${locale} localized chunks are reported. Size comparison tables include chunks that exist in both builds. Added and removed chunks are listed separately. Top 10 is sorted by max(before, after) size. Diff top 10 is sorted by absolute size diff. Startup chunks are the Vite entry for \`src/_boot_.ts\` and its static imports._`, `_Only ${locale} localized chunks are reported. Size comparison tables include chunks that exist in both builds. Added and removed chunks are listed separately. Top 10 is sorted by max(before, after) size. Diff top 10 is sorted by absolute size diff. Startup chunks are the Vite entry for \`src/_boot_.ts\` and its static imports._`,
'', '',
@ -437,7 +421,7 @@ jobs:
'<details>', '<details>',
`<summary>Largest</summary>`, `<summary>Largest</summary>`,
'', '',
markdownTable(topRows), markdownTable(largeRows),
'', '',
'</details>', '</details>',
'', '',