diff --git a/.github/badges/core-size.json b/.github/badges/core-size.json new file mode 100644 index 0000000..54497fb --- /dev/null +++ b/.github/badges/core-size.json @@ -0,0 +1,7 @@ +{ + "schemaVersion": 1, + "label": "bundle size", + "message": "385 B gzip", + "color": "brightgreen", + "cacheSeconds": 3600 +} diff --git a/README.md b/README.md index 8214d73..a4f6de9 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,15 @@ Zero runtime, zero React re-renders, and a simple developer experience. Say goodbye to context and prop-drilling. -bundle size npm version License: MIT ![CI](https://github.com/react-zero-ui/core/actions/workflows/ci.yml/badge.svg?branch=main) - -[See the proof](/docs/demo.md) [Quick Start](#quick-start) [API Reference](/docs/api-reference.md) [Usage Examples](/docs/usage-examples.md) [Migration Guide](/docs/migration-guide.md) [FAQ](/docs/faq.md) [Contributing](#contributing) +bundle size npm version License: MIT ![CI](https://github.com/react-zero-ui/core/actions/workflows/ci.yml/badge.svg?branch=main) + +[See the proof](/docs/demo.md)  |  +[Quick Start](#quick-start)  |  +[API Reference](/docs/api-reference.md)  |  +[Usage Examples](/docs/usage-examples.md)  |  +[Migration Guide](/docs/migration-guide.md)  |  +[FAQ](/docs/faq.md)  |  +[Contributing](#contributing) diff --git a/docs/size.md b/docs/size.md new file mode 100644 index 0000000..ce11131 --- /dev/null +++ b/docs/size.md @@ -0,0 +1,29 @@ +# Bundle Size Proof + +This repo measures bundle size from the built `@react-zero-ui/core` entry. + +## Command + +```bash +pnpm build +pnpm size +pnpm size:badge +``` + +The `size` script in [`package.json`](../package.json) runs: + +```bash +npx esbuild ./packages/core/dist/index.js --bundle --minify --format=esm --external:react --define:process.env.NODE_ENV='"production"' | gzip -c | wc -c +``` + +That produces the gzipped byte count used for the README badge. + +## Badge File + +Run `pnpm size:badge` after a build when you want to refresh the badge JSON. + +That writes: + +- [`core-size.json`](../.github/badges/core-size.json) + +The README badge reads from that committed file through a Shields endpoint. diff --git a/package.json b/package.json index e260490..831b41a 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,8 @@ "prepack:core": "pnpm -F @react-zero-ui/core pack --pack-destination ./dist", "reset": "git clean -fdx && pnpm install --frozen-lockfile && pnpm prepack:core && pnpm i-tarball", "size": "npx esbuild ./packages/core/dist/index.js --bundle --minify --format=esm --external:react --define:process.env.NODE_ENV='\"production\"' | gzip -c | wc -c", + "size:badge": "node scripts/write-size-badge.mjs", + "size:experimental-runtime": "sh -c 'out=$(mktemp); npx esbuild ./packages/core/dist/experimental/runtime.js --bundle --minify --format=esm --external:react --define:process.env.NODE_ENV=\"production\" > \"$out\" && cat \"$out\" && printf \"\\nExperimental runtime size: %s bytes\\n\" \"$(gzip -c \"$out\" | wc -c | tr -d \" \")\"'", "test": "eslint . && cd packages/core && pnpm test:all && pnpm smoke", "test:cli": "cd packages/core && pnpm test:cli", "test:integration": "cd packages/core && pnpm test:integration", diff --git a/scripts/write-size-badge.mjs b/scripts/write-size-badge.mjs new file mode 100644 index 0000000..ea6c7fa --- /dev/null +++ b/scripts/write-size-badge.mjs @@ -0,0 +1,34 @@ +import { execSync } from "node:child_process"; +import fs from "node:fs"; +import path from "node:path"; + +const outputPath = path.resolve(".github/badges/core-size.json"); +const rawBytes = execSync("pnpm size", { encoding: "utf8" }).trim(); +const match = rawBytes.match(/(\d+)\s*$/); +const bytes = match ? Number.parseInt(match[1], 10) : Number.NaN; + +if (!Number.isFinite(bytes)) { + throw new Error(`Expected pnpm size to return an integer byte count, got: ${rawBytes}`); +} + +const formatBytes = (value) => { + if (value < 1024) return `${value} B gzip`; + if (value < 1024 * 1024) return `${(value / 1024).toFixed(1).replace(/\\.0$/, "")} kB gzip`; + return `${(value / (1024 * 1024)).toFixed(1).replace(/\\.0$/, "")} MB gzip`; +}; + +const color = bytes < 512 ? "brightgreen" : bytes < 1024 ? "green" : bytes < 2048 ? "yellowgreen" : "yellow"; + +const badge = { + schemaVersion: 1, + label: "bundle size", + message: formatBytes(bytes), + color, + cacheSeconds: 3600, +}; + +fs.mkdirSync(path.dirname(outputPath), { recursive: true }); +fs.writeFileSync(outputPath, `${JSON.stringify(badge, null, 2)}\n`); + +console.log(`Wrote ${outputPath}`); +console.log(JSON.stringify(badge));