Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/scripts/create-glcanvas-entry.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { mkdir, writeFile } from "node:fs/promises";
import { dirname } from "node:path";

const output = process.env.CONSUMER_ENTRY;

if (!output) {
throw new Error("CONSUMER_ENTRY is required");
}

await mkdir(dirname(output), { recursive: true });
await writeFile(output, `export { glCanvas } from "@radiancejs/gl";`);
24 changes: 24 additions & 0 deletions .github/scripts/measure-size.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { gzipSync } from "node:zlib";
import { readFile, mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";

const reportDir = process.env.REPORT_DIR;
const libraryDist = process.env.LIBRARY_DIST;
const consumerDist = process.env.CONSUMER_DIST;

if (!reportDir || !libraryDist || !consumerDist) {
throw new Error("REPORT_DIR, LIBRARY_DIST, and CONSUMER_DIST are required");
}

const [library, consumer] = await Promise.all([
readFile(join(libraryDist, "index.js")),
readFile(join(consumerDist, "glcanvas-entry.js")),
]);
const report = {
libraryGzipBytes: gzipSync(library).byteLength,
glCanvasGzipBytes: gzipSync(consumer).byteLength,
};

await mkdir(reportDir, { recursive: true });
await writeFile(join(reportDir, "report.json"), `${JSON.stringify(report)}\n`);
console.log(report);
80 changes: 80 additions & 0 deletions .github/scripts/update-size-comment.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { readFile } from "node:fs/promises";

const token = process.env.GITHUB_TOKEN;
const repository = process.env.GITHUB_REPOSITORY;
const issueNumber = process.env.PR_NUMBER;
const prReportPath = process.env.PR_REPORT;
const baseReportPath = process.env.BASE_REPORT;

if (!token || !repository || !issueNumber || !prReportPath || !baseReportPath) {
throw new Error(
"GITHUB_TOKEN, GITHUB_REPOSITORY, PR_NUMBER, PR_REPORT, and BASE_REPORT are required",
);
}

const [owner, repo] = repository.split("/");
const pr = JSON.parse(await readFile(prReportPath, "utf8"));
let base = null;

try {
base = JSON.parse(await readFile(baseReportPath, "utf8"));
} catch {
// The base report is optional when its main-branch cache is unavailable.
}

const format = (bytes: number) => `${(bytes / 1024).toFixed(2)} kB`;
const delta = (current: number, previous?: number) => {
if (previous === undefined || previous === null) return "";
const difference = current - previous;
const sign = difference > 0 ? "+" : "";
const icon = difference > 0 ? " 🔺" : difference < 0 ? " 🎉" : "";
const percentage = ` (${sign}${((difference / previous) * 100).toFixed(1)}%${icon})`;
return `${sign}${format(difference)}${percentage}`;
};
const row = (name: string, key: keyof typeof pr) =>
`| ${name} | ${base ? format(base[key]) : ""} | ${format(pr[key])} | ${delta(pr[key], base?.[key])} |`;
const marker = "<!-- radiance-size-report -->";
const body = [
marker,
"## Bundle size",
"",
"| Bundle | Base | PR | Delta |",
"| --- | ---: | ---: | ---: |",
row("`lib/dist/index.js`", "libraryGzipBytes"),
row("`glCanvas`", "glCanvasGzipBytes"),
].join("\n");

const api = `https://api.github.com/repos/${owner}/${repo}`;
const headers = {
Accept: "application/vnd.github+json",
Authorization: `Bearer ${token}`,
"X-GitHub-Api-Version": "2022-11-28",
};
const commentsResponse = await fetch(`${api}/issues/${issueNumber}/comments?per_page=100`, {
headers,
});

if (!commentsResponse.ok) {
throw new Error(
`Unable to list comments: ${commentsResponse.status} ${await commentsResponse.text()}`,
);
}

const comments = await commentsResponse.json();
const existing = comments.find((comment: { body?: string }) => comment.body?.includes(marker));
const request = existing
? fetch(`${api}/issues/comments/${existing.id}`, {
method: "PATCH",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ body }),
})
: fetch(`${api}/issues/${issueNumber}/comments`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ body }),
});

const response = await request;
if (!response.ok) {
throw new Error(`Unable to update comment: ${response.status} ${await response.text()}`);
}
79 changes: 71 additions & 8 deletions .github/workflows/size.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
name: Size

on:
push:
branches:
- main
pull_request:
branches:
- main
Expand All @@ -16,17 +19,77 @@ env:
jobs:
size:
runs-on: ubuntu-latest
env:
CI_JOB_NUMBER: 1
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 1
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
with:
version: ${{ env.PNPM_VERSION }}
- run: pnpm --filter="./lib" install
- uses: andresz1/size-limit-action@94bc357df29c36c8f8d50ea497c3e225c3c95d1d # v1.8.0
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
directory: lib/
build_script: build:lib
package_manager: pnpm
node-version: ${{ env.NODE_VERSION }}
cache: pnpm

- name: Restore base size report
if: github.event_name == 'pull_request'
uses: actions/cache/restore@v4
with:
path: ${{ runner.temp }}/base-size-report
key: bundle-size-${{ github.event.pull_request.base.sha }}

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build library
run: pnpm --filter="./lib" build:lib

- name: Create glCanvas entry
env:
CONSUMER_ENTRY: ${{ github.workspace }}/benchmark/.size/glcanvas-entry.ts
run: node .github/scripts/create-glcanvas-entry.mts

- name: Transpile and minify bundles
env:
CONSUMER_ENTRY: ${{ github.workspace }}/benchmark/.size/glcanvas-entry.ts
LIBRARY_DIST: ${{ runner.temp }}/library-dist
CONSUMER_DIST: ${{ runner.temp }}/consumer-dist
run: |
pnpm --filter="./lib" exec tsdown dist/index.js \
--no-config \
--format esm \
--platform browser \
--target es2022 \
--minify \
--out-dir "$LIBRARY_DIST"
pnpm --filter="./lib" exec tsdown "$CONSUMER_ENTRY" \
--no-config \
--format esm \
--platform browser \
--target es2022 \
--minify \
--out-dir "$CONSUMER_DIST"

- name: Measure gzip sizes
id: measure
env:
REPORT_DIR: ${{ runner.temp }}/size-report
LIBRARY_DIST: ${{ runner.temp }}/library-dist
CONSUMER_DIST: ${{ runner.temp }}/consumer-dist
run: node .github/scripts/measure-size.mts

- name: Save main size report
if: github.event_name == 'push'
uses: actions/cache/save@v4
with:
path: ${{ runner.temp }}/size-report
key: bundle-size-${{ github.sha }}

- name: Update pull request comment
if: github.event_name == 'pull_request'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_REPORT: ${{ runner.temp }}/size-report/report.json
BASE_REPORT: ${{ runner.temp }}/base-size-report/report.json
run: node .github/scripts/update-size-comment.mts
2 changes: 1 addition & 1 deletion benchmark/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"measure": "node ./scripts/build-and-measure.mts"
},
"dependencies": {
"@radiancejs/gl": "0.11.1",
"@radiancejs/gl": "workspace:*",
"ogl": "1.0.11",
"three": "0.185.1",
"twgl.js": "7.0.0"
Expand Down
4 changes: 2 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading