mirror of
https://github.com/zoriya/v10.git
synced 2026-08-05 13:48:14 +00:00
chore(ci): add turbo caching and replace size-limit (#524)
This commit is contained in:
@@ -9,7 +9,7 @@ permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
size:
|
||||
pr-size:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -25,191 +25,96 @@ jobs:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install and build PR
|
||||
- name: Cache turbo build setup
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: .turbo
|
||||
key: ${{ runner.os }}-turbo-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-turbo-
|
||||
|
||||
- name: Install and build
|
||||
run: pnpm install && pnpm build:packages
|
||||
|
||||
- name: Measure PR bundle size
|
||||
run: pnpm -w exec size-limit --json > /tmp/pr-size.json
|
||||
- name: Measure bundle size
|
||||
run: node .github/scripts/bundle-size.js --json pr-size.json
|
||||
|
||||
- name: Measure base bundle size
|
||||
- name: Upload size data
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pr-size
|
||||
path: pr-size.json
|
||||
|
||||
base-size:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout base
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.base_ref }}
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Cache turbo build setup
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: .turbo
|
||||
key: ${{ runner.os }}-turbo-${{ github.event.pull_request.base.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-turbo-
|
||||
|
||||
- name: Install and build
|
||||
run: |
|
||||
git fetch origin ${{ github.base_ref }} --depth=1
|
||||
git checkout -f FETCH_HEAD
|
||||
|
||||
pnpm install
|
||||
|
||||
if [ -f .size-limit.json ]; then
|
||||
if [ -f .github/scripts/bundle-size.js ]; then
|
||||
pnpm build:packages
|
||||
pnpm -w exec size-limit --json > /tmp/base-size.json
|
||||
node .github/scripts/bundle-size.js --json base-size.json
|
||||
else
|
||||
echo '[]' > /tmp/base-size.json
|
||||
echo '[]' > base-size.json
|
||||
fi
|
||||
|
||||
- name: Report
|
||||
- name: Upload size data
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: base-size
|
||||
path: base-size.json
|
||||
|
||||
report:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [pr-size, base-size]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Download size data
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
- name: Generate report
|
||||
run: >
|
||||
node .github/scripts/bundle-size-report.js
|
||||
--pr artifacts/pr-size/pr-size.json
|
||||
--base artifacts/base-size/base-size.json
|
||||
> report.md
|
||||
|
||||
- name: Post comment
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
|
||||
const pr = JSON.parse(fs.readFileSync('/tmp/pr-size.json', 'utf8'));
|
||||
const base = JSON.parse(fs.readFileSync('/tmp/base-size.json', 'utf8'));
|
||||
|
||||
const baseMap = Object.fromEntries(base.map(e => [e.name, e.size]));
|
||||
|
||||
function formatBytes(bytes) {
|
||||
if (bytes < 1024) return `${bytes} B`;
|
||||
return `${(bytes / 1024).toFixed(2)} kB`;
|
||||
}
|
||||
|
||||
function formatDelta(current, previous) {
|
||||
if (previous === undefined) return { bytes: '—', pct: '' };
|
||||
const diff = current - previous;
|
||||
if (diff === 0) return { bytes: '0 B', pct: '0%' };
|
||||
const sign = diff > 0 ? '+' : '-';
|
||||
const pct = Math.abs((diff / previous) * 100).toFixed(1);
|
||||
return { bytes: `${sign}${formatBytes(Math.abs(diff))}`, pct: `${sign}${pct}%` };
|
||||
}
|
||||
|
||||
function statusIcon(current, previous) {
|
||||
if (previous === undefined) return '🆕';
|
||||
const diff = current - previous;
|
||||
if (diff === 0) return '✅';
|
||||
if (diff < 0) return '🔽';
|
||||
const pct = (diff / previous) * 100;
|
||||
return pct > 10 ? '🔴' : '🔺';
|
||||
}
|
||||
|
||||
// Delta bar: visualizes % change relative to the largest change
|
||||
function deltaBar(current, previous, maxAbsPct) {
|
||||
const width = 8;
|
||||
if (previous === undefined || maxAbsPct === 0) return '░'.repeat(width);
|
||||
const pct = Math.abs(((current - previous) / previous) * 100);
|
||||
const filled = Math.round((pct / maxAbsPct) * width);
|
||||
return '█'.repeat(filled) + '░'.repeat(width - filled);
|
||||
}
|
||||
|
||||
// Group entries by package: @videojs/utils/* -> utils, @videojs/store/* -> store, etc.
|
||||
const groups = new Map();
|
||||
for (const entry of pr) {
|
||||
const match = entry.name.match(/^@videojs\/([^/]+)/);
|
||||
const pkg = match ? match[1] : 'other';
|
||||
if (!groups.has(pkg)) groups.set(pkg, []);
|
||||
groups.get(pkg).push(entry);
|
||||
}
|
||||
|
||||
// First pass: compute per-package totals
|
||||
const pkgData = [];
|
||||
let grandTotalPr = 0;
|
||||
let grandTotalBase = 0;
|
||||
|
||||
for (const [pkg, entries] of groups) {
|
||||
const pkgTotalPr = entries.reduce((s, e) => s + e.size, 0);
|
||||
const pkgTotalBase = entries.reduce((s, e) => s + (baseMap[e.name] ?? 0), 0);
|
||||
const hasBase = entries.some(e => baseMap[e.name] !== undefined);
|
||||
grandTotalPr += pkgTotalPr;
|
||||
grandTotalBase += pkgTotalBase;
|
||||
|
||||
const pkgPrev = entries.length > 1 ? pkgTotalBase : baseMap[entries[0].name];
|
||||
const pkgCur = entries.length > 1 ? pkgTotalPr : entries[0].size;
|
||||
const changed = hasBase && pkgCur !== pkgPrev;
|
||||
|
||||
pkgData.push({ pkg, entries, pkgTotalPr, pkgTotalBase, hasBase, pkgPrev, pkgCur, changed });
|
||||
}
|
||||
|
||||
const maxAbsPct = Math.max(
|
||||
...pkgData.map(p => {
|
||||
if (!p.hasBase || p.pkgPrev === 0) return 0;
|
||||
return Math.abs(((p.pkgCur - p.pkgPrev) / p.pkgPrev) * 100);
|
||||
})
|
||||
);
|
||||
|
||||
// Overview table
|
||||
const overview = [];
|
||||
overview.push('| Package | Size | Diff | | % | |');
|
||||
overview.push('|---|--:|--:|---|--:|:-:|');
|
||||
|
||||
for (const p of pkgData) {
|
||||
const d = formatDelta(p.pkgCur, p.pkgPrev);
|
||||
const icon = p.hasBase ? statusIcon(p.pkgCur, p.pkgPrev) : '';
|
||||
const bar = `\`${deltaBar(p.pkgCur, p.pkgPrev, maxAbsPct)}\``;
|
||||
overview.push(
|
||||
`| **@videojs/${p.pkg}** | **${formatBytes(p.pkgCur)}** | ${p.hasBase ? d.bytes : '—'} | ${bar} | ${p.hasBase ? d.pct : ''} | ${icon} |`
|
||||
);
|
||||
}
|
||||
|
||||
// Detail sections
|
||||
const details = [];
|
||||
details.push('#### Subpath Breakdown');
|
||||
details.push('');
|
||||
|
||||
for (const p of pkgData) {
|
||||
const { pkg, entries, pkgTotalPr, pkgTotalBase, hasBase } = p;
|
||||
|
||||
// Subpath display: @videojs/utils/dom -> ./dom, @videojs/store -> .
|
||||
const displayName = (name) => {
|
||||
const sub = name.replace(`@videojs/${pkg}`, '');
|
||||
return sub ? `.${sub}` : '.';
|
||||
};
|
||||
|
||||
details.push(`<details>`);
|
||||
details.push(`<summary><code>@videojs/${pkg}</code></summary>`);
|
||||
details.push('');
|
||||
details.push('| Subpath | Base | PR | Diff | % | |');
|
||||
details.push('|---|--:|--:|--:|--:|:-:|');
|
||||
|
||||
for (const entry of entries) {
|
||||
const prev = baseMap[entry.name];
|
||||
const d = formatDelta(entry.size, prev);
|
||||
details.push(
|
||||
`| \`${displayName(entry.name)}\` | ${prev !== undefined ? formatBytes(prev) : '—'} | **${formatBytes(entry.size)}** | ${d.bytes} | ${d.pct} | ${statusIcon(entry.size, prev)} |`
|
||||
);
|
||||
}
|
||||
|
||||
if (entries.length > 1) {
|
||||
const d = formatDelta(pkgTotalPr, pkgTotalBase);
|
||||
details.push(
|
||||
`| **total** | **${hasBase ? formatBytes(pkgTotalBase) : '—'}** | **${formatBytes(pkgTotalPr)}** | **${hasBase ? d.bytes : '—'}** | **${hasBase ? d.pct : ''}** | |`
|
||||
);
|
||||
}
|
||||
|
||||
details.push('');
|
||||
details.push('</details>');
|
||||
details.push('');
|
||||
}
|
||||
|
||||
const grandDelta = formatDelta(grandTotalPr, grandTotalBase);
|
||||
|
||||
const body = fs.readFileSync('report.md', 'utf8');
|
||||
const marker = '<!-- bundle-size-report -->';
|
||||
const body = [
|
||||
marker,
|
||||
'### 📦 Bundle Size Report',
|
||||
'',
|
||||
...overview,
|
||||
'',
|
||||
`**Total: ${formatBytes(grandTotalPr)}**${grandTotalBase ? ` · ${grandDelta.bytes} · ${grandDelta.pct}` : ''}`,
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
...details,
|
||||
'---',
|
||||
'',
|
||||
'<details>',
|
||||
'<summary>ℹ️ How to interpret</summary>',
|
||||
'',
|
||||
'Each package shows its own code size with workspace and peer dependencies externalized.',
|
||||
'Sizes are minified + brotli, measured via [size-limit](https://github.com/ai/size-limit) with esbuild.',
|
||||
'',
|
||||
'| Icon | Meaning |',
|
||||
'|---|---|',
|
||||
'| ✅ | No change |',
|
||||
'| 🔺 | Increased ≤ 10% |',
|
||||
'| 🔴 | Increased > 10% |',
|
||||
'| 🔽 | Decreased |',
|
||||
'| 🆕 | New (no baseline) |',
|
||||
'',
|
||||
'Run `pnpm size` locally to check current sizes.',
|
||||
'</details>',
|
||||
].join('\n');
|
||||
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
|
||||
@@ -55,6 +55,15 @@ jobs:
|
||||
if: ${{ steps.release.outputs.releases_created == 'true' }}
|
||||
run: pnpm i --frozen-lockfile
|
||||
|
||||
- name: Cache turbo build setup
|
||||
if: ${{ steps.release.outputs.releases_created == 'true' }}
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: .turbo
|
||||
key: ${{ runner.os }}-turbo-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-turbo-
|
||||
|
||||
- name: Clean
|
||||
if: ${{ steps.release.outputs.releases_created == 'true' }}
|
||||
run: pnpm clean
|
||||
|
||||
@@ -28,5 +28,13 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Cache turbo build setup
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: .turbo
|
||||
key: ${{ runner.os }}-turbo-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-turbo-
|
||||
|
||||
- name: Build
|
||||
run: pnpm build:packages
|
||||
|
||||
@@ -30,5 +30,13 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Cache turbo build setup
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: .turbo
|
||||
key: ${{ runner.os }}-turbo-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-turbo-
|
||||
|
||||
- name: Run website tests
|
||||
run: pnpm --filter site test
|
||||
|
||||
Reference in New Issue
Block a user