diff --git a/.github/scripts/compare-packages-size.js b/.github/scripts/compare-packages-size.js new file mode 100644 index 0000000..172b39e --- /dev/null +++ b/.github/scripts/compare-packages-size.js @@ -0,0 +1,60 @@ +import path from "node:path"; +import { execSync as exec } from "node:child_process"; +import { statSync as stat, existsSync as exists } from "node:fs"; +import { globSync as glob } from "glob"; + +function size(file) { + return exists(file) ? stat(file).size : null; +} + +function format(bytes) { + if (bytes == null) { + return "—"; + } + + return bytes >= 1024 + ? `${(bytes / 1024).toFixed(2)} KB` + : `${bytes} B`; +} + +function delta(a, b) { + if (a == null || b == null) { + return null; + } + return a - b; +} + +function icon(d) { + if (d == null) { + return "—"; + } + + if (d > 0) return "⬆️"; + if (d < 0) return "⬇️"; + return "➡️"; +} + +const pr_files = glob("dist/**/*.min.js"); +const pr_sizes = Object.fromEntries(pr_files.map(f => [f, size(f)])); + +exec("git fetch origin main", { stdio: "inherit" }); +exec("git checkout origin/main", { stdio: "ignore" }); +exec("npm ci --include=dev", { stdio: "inherit" }); +exec("npm run build", { stdio: "inherit" }); + +const main_sizes = Object.fromEntries(pr_files.map(f => [f, size(f)])); + +let md = ` +### 📦 Bundle size comparison + +| Name | main | PR | Δ | +|------|------|----|---| +`; + +for (const file of pr_files) { + const d = delta(pr_sizes[file], main_sizes[file]); + + md += `| \`${path.basename(file)}\` | ${format(main_sizes[file])} | ${format(pr_sizes[file])} | ${icon(d)} ${format(d)} |\n`; +} + +console.log(md); diff --git a/.github/workflows/pr-diff-size.yml b/.github/workflows/pr-diff-size.yml new file mode 100644 index 0000000..691562d --- /dev/null +++ b/.github/workflows/pr-diff-size.yml @@ -0,0 +1,76 @@ +name: Packages size analysis + +on: + pull_request: + branches: [main] + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + contents: read + pull-requests: write + actions: read + +jobs: + analyze: + if: github.repository == 'rameel/ramstack.alpinegear.js' + + runs-on: ubuntu-latest + + steps: + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '24' + registry-url: 'https://registry.npmjs.org' + + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Dependencies + run: npm ci + + - name: Build + run: npm run build + env: + NODE_ENV: production + SKIP_GIT_TAG_RESOLUTION: true + + - name: Run size comparison + run: npm run size-diff-report > comment.md + env: + NODE_ENV: production + SKIP_GIT_TAG_RESOLUTION: true + + - name: Comment PR + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const body = fs.readFileSync('./comment.md', 'utf8'); + const pr_number = context.payload.workflow_run.pull_requests[0].number; + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr_number + }); + + const marker = "### 📦 Bundle size comparison"; + const existing_comment = comments.find(c => c.body.includes(marker)); + + if (existing_comment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing_comment.id, + body: body + }); + } + else { + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }) + } diff --git a/gulpfile.js b/gulpfile.js index bb8c1a5..97429c6 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -9,13 +9,14 @@ import { rimraf } from "rimraf"; import { rollup } from "rollup"; const is_production = process.env.NODE_ENV === "production"; +const skip_git_tag_resolution = process.env.SKIP_GIT_TAG_RESOLUTION === "true"; const task_delete = create_task("delete -> delete build folders", () => { return rimraf(["dist", "coverage", "docs/public/js"]); }); const task_update_packages = create_task("update -> update version", async done => { - if (is_production) { + if (is_production && !skip_git_tag_resolution) { const current_version = await obtain_version_from_tag(); const update_version = data => { diff --git a/package.json b/package.json index 33e7095..a18dfaa 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "scripts": { "build": "cross-env NODE_ENV=production gulp build", "build:debug": "gulp build", + "size-diff-report": "node .github/scripts/compare-packages-size.js", "test": "gulp build && vitest run && playwright test", "test:playwright": "playwright test", "test:vitest": "vitest run"