From 89132f67458937af3e14f93497ebf928ad8aa095 Mon Sep 17 00:00:00 2001 From: Anders Olsson Date: Wed, 3 Jun 2026 23:28:36 +0200 Subject: [PATCH] ci(web): typecheck/lint/test/build + bundle-size budget Co-Authored-By: Claude Sonnet 4.6 --- .gitea/workflows/ci.yaml | 29 +++++++++++++++++++++++++++++ web/package.json | 3 ++- web/scripts/check-bundle-size.mjs | 20 ++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 .gitea/workflows/ci.yaml create mode 100644 web/scripts/check-bundle-size.mjs diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml new file mode 100644 index 0000000..ba217a4 --- /dev/null +++ b/.gitea/workflows/ci.yaml @@ -0,0 +1,29 @@ +name: CI + +on: + push: + branches: ["**"] + pull_request: + +jobs: + web: + runs-on: ubuntu-latest + defaults: + run: + working-directory: web + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 9 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + cache-dependency-path: web/pnpm-lock.yaml + - run: pnpm install --frozen-lockfile + - run: pnpm typecheck + - run: pnpm lint + - run: pnpm test + - run: pnpm build + - run: pnpm check:size diff --git a/web/package.json b/web/package.json index f8d221b..15d012d 100644 --- a/web/package.json +++ b/web/package.json @@ -11,7 +11,8 @@ "test:watch": "vitest", "typecheck": "tsc -b --noEmit", "lint": "eslint .", - "gen:api": "openapi-typescript http://localhost:8080/api-docs/openapi.json -o src/api/schema.d.ts" + "gen:api": "openapi-typescript http://localhost:8080/api-docs/openapi.json -o src/api/schema.d.ts", + "check:size": "node scripts/check-bundle-size.mjs" }, "dependencies": { "@base-ui/react": "^1.5.0", diff --git a/web/scripts/check-bundle-size.mjs b/web/scripts/check-bundle-size.mjs new file mode 100644 index 0000000..65105ef --- /dev/null +++ b/web/scripts/check-bundle-size.mjs @@ -0,0 +1,20 @@ +// Fails if the largest built JS entry chunk exceeds the gzipped budget. +import { readdirSync, readFileSync } from "node:fs"; +import { gzipSync } from "node:zlib"; +import { join } from "node:path"; + +const BUDGET_KB = 150; +const dir = "dist/assets"; +const jsFiles = readdirSync(dir).filter((f) => f.endsWith(".js")); +let largest = 0; +let largestName = ""; +for (const file of jsFiles) { + const gz = gzipSync(readFileSync(join(dir, file))).length; + if (gz > largest) { largest = gz; largestName = file; } +} +const kb = (largest / 1024).toFixed(1); +console.log(`largest JS chunk: ${largestName} = ${kb} KB gz (budget ${BUDGET_KB} KB)`); +if (largest > BUDGET_KB * 1024) { + console.error(`bundle-size budget exceeded: ${kb} KB > ${BUDGET_KB} KB`); + process.exit(1); +}