Skip to content

size analysis workflow #76

size analysis workflow

size analysis workflow #76

name: Bundle Analysis
on:
pull_request:
branches: [main]
jobs:
analyze:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup bun
uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- name: Install dependencies
run: bun install
- name: Build PR branch
run: |
bun run build
mkdir -p /tmp/dist-pr
cp -r dist/* /tmp/dist-pr/
cp stats.json /tmp/dist-pr/
- name: Build main branch
continue-on-error: true
id: main-build
run: |
git stash -u
git checkout main
bun install
if bun run build; then
mkdir -p /tmp/dist-main
cp -r dist/* /tmp/dist-main/
cp stats.json /tmp/dist-main/ || true
echo "main_build_success=true" >> $GITHUB_OUTPUT
else
echo "main_build_success=false" >> $GITHUB_OUTPUT
fi
- name: Create analysis script
run: |
echo 'import { readFileSync, readdirSync, writeFileSync } from "fs";
function analyzeBundle(buildPath) {
try {
const stats = JSON.parse(readFileSync(`${buildPath}/stats.json`, "utf-8"));
// Calculate total size from all modules
const totalSize = stats.children?.[0]?.gzipSize || 0;
// Analyze chunks
const chunks = {
main: 0,
vendors: 0,
runtime: 0
};
// Handle new visualizer format
if (stats.children?.[0]?.groups) {
stats.children[0].groups.forEach(group => {
if (group.label.includes("vendor")) chunks.vendors += group.gzipSize || 0;
else if (group.label.includes("runtime")) chunks.runtime += group.gzipSize || 0;
else chunks.main += group.gzipSize || 0;
});
}
// Analyze dependencies
const deps = {};
if (stats.children?.[0]?.groups) {
stats.children[0].groups
.filter(g => g.label.includes("node_modules"))
.forEach(g => {
const depName = g.label.split("node_modules/")[1]?.split("/")[0];
if (depName) {
deps[depName] = (deps[depName] || 0) + (g.gzipSize || 0);
}
});
}
return {
totalSize,
chunks,
dependencies: Object.entries(deps)
.sort(([,a], [,b]) => b - a)
.slice(0, 6) // Top 6 dependencies
};
} catch (error) {
console.error(`Error analyzing bundle at ${buildPath}:`, error);
return null;
}
}
function formatSize(bytes) {
return (bytes / 1024).toFixed(1) + " KB";
}
const prAnalysis = analyzeBundle("/tmp/dist-pr") || {
totalSize: 0,
chunks: { main: 0, vendors: 0, runtime: 0 },
dependencies: []
};
const mainAnalysis = process.env.MAIN_BUILD_SUCCESS === "true"
? analyzeBundle("/tmp/dist-main")
: null;
const report = {
totalSize: formatSize(prAnalysis.totalSize),
chunks: Object.entries(prAnalysis.chunks).map(([name, size]) => ({
name,
size: formatSize(size),
// Only include diff if mainAnalysis exists and has the chunk
diff: mainAnalysis && mainAnalysis.chunks[name] !== undefined
? formatSize(size - mainAnalysis.chunks[name])
: null
})),
dependencies: prAnalysis.dependencies.map(([name, size]) => ({
name,
size: formatSize(size),
// Only include diff if mainAnalysis exists and has the dependency
diff: mainAnalysis?.dependencies.find(([n]) => n === name)?.[1] !== undefined
? formatSize(size - mainAnalysis.dependencies.find(([n]) => n === name)[1])
: null
}))
};
console.log("Writing output:", JSON.stringify(report));
writeFileSync("output.json", JSON.stringify(report));' > analyze.js
- name: Generate size report
id: size-report
run: |
MAIN_BUILD_SUCCESS=${{ steps.main-build.outputs.main_build_success }} node analyze.js
echo "report=$(cat output.json)" >> $GITHUB_OUTPUT
- name: Add PR Comment
uses: mshick/add-pr-comment@v2
with:
message: |
# 📦 Bundle Size Analysis
Total Bundle Size: ${{ fromJSON(steps.size-report.outputs.totalSize) }}
## Chunk Distribution
```
${{ join(fromJSON(steps.size-report.outputs.chunks).*.name, ': ') }}
${{ join(fromJSON(steps.size-report.outputs.chunks).*.size, ' ') }}
${{ steps.main-build.outputs.main_build_success == 'true' &&
join(fromJSON(steps.size-report.outputs.chunks).*.diff, ' ') || '' }}
```
## Top Dependencies
```
${{ join(fromJSON(steps.size-report.outputs.dependencies).*.name, ': ') }}
${{ join(fromJSON(steps.size-report.outputs.dependencies).*.size, ' ') }}
${{ steps.main-build.outputs.main_build_success == 'true' &&
join(fromJSON(steps.size-report.outputs.dependencies).*.diff, ' ') || '' }}
```
proxy-url: https://add-pr-comment-proxy-tscircuit.vercel.app/api
repo-token: ${{ secrets.GITHUB_TOKEN }}
allow-repeats: false