From cc7f1e736668b76452736045299358abb46c985c Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sat, 20 Jun 2026 11:49:15 +0900 Subject: [PATCH] =?UTF-8?q?enhance(dev/frontend-js-size):=20diff=E3=81=8C?= =?UTF-8?q?=E5=A4=A7=E3=81=8D=E3=81=84=E9=A0=86=E3=81=AB=E3=82=BD=E3=83=BC?= =?UTF-8?q?=E3=83=88=E3=81=97=E3=81=9F=E4=B8=8A=E4=BD=8D10=E3=83=81?= =?UTF-8?q?=E3=83=A3=E3=83=B3=E3=82=AF=E3=81=AE=E8=A1=A8=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/frontend-js-size.yml | 53 ++++++++++++++++++++------ 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/.github/workflows/frontend-js-size.yml b/.github/workflows/frontend-js-size.yml index 7d3641355b..67d4e050c6 100644 --- a/.github/workflows/frontend-js-size.yml +++ b/.github/workflows/frontend-js-size.yml @@ -137,6 +137,11 @@ jobs: return `${sign}${formatBytes(Math.abs(diff))}`; } + function sizeDiff(beforeSize, afterSize) { + if (beforeSize == null && afterSize == null) return null; + return (afterSize ?? 0) - (beforeSize ?? 0); + } + function escapeCell(value) { return String(value).replaceAll('|', '\\|').replaceAll('\n', '
'); } @@ -251,19 +256,19 @@ jobs: file: entryDisplayName(afterEntry ?? beforeEntry), beforeSize, afterSize, - diff: beforeSize == null || afterSize == null ? null : afterSize - beforeSize, + diff: sizeDiff(beforeSize, afterSize), sortSize: Math.max(beforeSize ?? 0, afterSize ?? 0), }; }); } - function markdownTable(rows) { + function markdownTable(rows, emptyMessage = '_No JavaScript chunks found._') { if (rows.length === 0) { - return '_No JavaScript chunks found._'; + return emptyMessage; } const lines = [ - '| File | Size (before) | Size (after) | Size (diff) |', + '| File | Before | After | Diff |', '| --- | ---: | ---: | ---: |', ]; for (const row of rows) { @@ -283,6 +288,25 @@ jobs: .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.file.localeCompare(b.file); + } + + function topDiffKeys(before, after) { + const allKeys = new Set([ + ...Object.keys(before.chunks), + ...Object.keys(after.chunks), + ]); + return compareRows([...allKeys], before, after) + .filter((row) => row.diff !== 0 && row.diff != null) + .sort(compareDiffRows) + .slice(0, topLimit) + .map((row) => row.key); + } + const beforeDir = process.argv[2]; const afterDir = process.argv[3]; const outFile = process.argv[4]; @@ -295,6 +319,9 @@ jobs: const topRows = compareRows(unionTopKeys(before, after), before, after) .sort((a, b) => b.sortSize - a.sortSize || a.file.localeCompare(b.file)); + const diffRows = compareRows(topDiffKeys(before, after), before, after) + .sort(compareDiffRows); + const startupKeys = new Set([ ...before.startupKeys, ...after.startupKeys, @@ -304,21 +331,23 @@ jobs: const body = [ marker, - '## Frontend JavaScript size', + '## Frontend size report', '', - `Compared locale: \`${locale}\``, - `Before: \`${beforeSha}\``, - `After: \`${afterSha}\``, + '### Top 10 largest chunk diffs', '', - '### Top 10 largest JS chunks', + markdownTable(diffRows, '_No JavaScript chunk size changes found._'), '', + '### Top 10 largest chunks', + '
', markdownTable(topRows), + '
', '', - '### Startup JS chunks', - '', + '### Startup chunks', + '
', markdownTable(startupRows), '', - '_Top 10 is sorted by max(before, after) size. Startup chunks are the Vite entry for `src/_boot_.ts` and its static imports._', + '_Top 10 is sorted by max(before, after) size. Diff top 10 is sorted by absolute size diff, with missing chunks compared against 0 B. Startup chunks are the Vite entry for `src/_boot_.ts` and its static imports._', + '
', '', ].join('\n');