Repository navigation
Add collaborative spreadsheet blocks inside documents #539
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: WASM bundle size | |
| # Phase 5 M-P9 piece B — bundle-size CI gate. | |
| # | |
| # Builds the frontend with `trunk build --release` (so wasm-opt=z | |
| # runs, matching the deployed artifact), measures the gzipped | |
| # `*_bg.wasm`, and fails the build if it exceeds the threshold | |
| # codified in design/performance-budgets.md. | |
| # | |
| # Threshold tracks the current measured baseline plus ~7% headroom, | |
| # not the aspirational 800 KB figure. A separate optimization | |
| # track tightens it; this gate just stops further regression. See | |
| # the "Ratchet, not anchor" subsection in performance-budgets.md. | |
| on: | |
| push: | |
| # `main` is the default branch of the public repo (the pre-OSS | |
| # private repo used `master`). With the stale name this gate never | |
| # ran on default-branch pushes, so the bundle drifted ~5.4 KB past | |
| # the limit unseen — see the 2026-07-08 rebaseline below. | |
| branches: [main] | |
| pull_request: | |
| concurrency: | |
| group: bundle-size-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| CARGO_TERM_COLOR: always | |
| # Hard threshold in bytes — change this only in lockstep with | |
| # `design/performance-budgets.md`'s "CI gate threshold" row. The | |
| # gate steps DOWN as bundle-shrinking work lands; bumps UP require | |
| # an explicit, doc-noted reason. | |
| # | |
| # 2026-06-03 re-baseline: the measured bundle reached 2,168,852 B | |
| # gzipped (~2.07 MiB) — ~2 weeks of accumulated Phase-5 features off | |
| # the stale 1.87 MB / 2026-05-21 baseline (link sharing was the last | |
| # ~10–30 KB that crossed the old 2.0 MiB gate). | |
| # | |
| # 2026-06-04 ratchet DOWN: deploy builds now apply size-optimizing | |
| # profile overrides (CARGO_PROFILE_RELEASE_OPT_LEVEL=z, LTO=fat, | |
| # CODEGEN_UNITS=1, STRIP, PANIC=abort — see the "Build frontend" step | |
| # and Dockerfile Stage 2) plus wasm-opt --all-features. Measured | |
| # bundle dropped to ~1,425,747 B gzipped (~1.36 MiB), a ~34% cut. | |
| # Gate set to the new measurement + ~9% headroom (absorbs local↔CI | |
| # toolchain drift); tighten after the first CI baseline confirms. | |
| # See performance-budgets.md → "Bundle size". | |
| # | |
| # 2026-07-02 rebaseline: #142 Phase 2 mail-merge added the values-fill | |
| # form + the placeholder DTO on TemplateItem, pushing the measured | |
| # bundle to 1,561,511 B — ~11 KB over the previous 1,550,000 limit. | |
| # Bumping to 1,600,000 (~1.52 MiB) with ~40 KB headroom to absorb | |
| # Phase 3 (Sample gallery) without a further churn. | |
| # | |
| # 2026-07-04 rebaseline: #137 Kanban Phase 2 added the card modal, | |
| # click observer, and column/card commands; #136 Calendar fixes | |
| # added the data-atom-size DOM walk handlers. Measured bundle | |
| # 1,616,644 B — ~17 KB over the previous 1,600,000 limit. | |
| # Bumping to 1,650,000 (~1.57 MiB) with ~33 KB headroom for | |
| # incremental Phase 5 work. | |
| # | |
| # 2026-07-08 rebaseline: the `push` trigger above was still `master` | |
| # after the 2026-07-07 re-publish switched the default branch to | |
| # `main`, so the gate never ran on default-branch pushes and the | |
| # 33 KB headroom eroded unseen. Two unrelated PRs off the same | |
| # merge-base (9b2ae1f) measured 1,655,497 B and 1,655,687 B — 190 B | |
| # apart, proving the drift is on main, not in either diff. Bumping | |
| # to 1,700,000 (~1.62 MiB) ≈ measurement + ~2.7% headroom; ratchet | |
| # down after the first green main run establishes a fresh baseline. | |
| # | |
| # 2026-07-09 rebaseline: PR #23 (code-block syntax highlighting, | |
| # +17.6 KB measured against its merge-base) tripped the gate at | |
| # 1,702,855 B — 2,855 B over. Attribution in issue #21: main-side | |
| # growth since 2026-07-02 (Mermaid slice 2 #17, coverage suite, | |
| # et al.) consumed the headroom; the highlighting branch was the | |
| # straw. Bumping to 1,850,000 (~1.76 MiB) ≈ measurement + ~8.6% | |
| # headroom, matching the 2026-06-04 ratio. The optimization / | |
| # ratchet-down pass stays tracked in #21 — do not bump again | |
| # without closing or updating that issue. | |
| # | |
| # 2026-07-10 optimization pass (#21, closed): measured 1,743,301 B | |
| # on main at 07c0514 (~6.1% headroom). twiggy attribution and two | |
| # tested levers concluded the bundle is efficiently packed — | |
| # opt-level=z + fat LTO + wasm-opt -z + pervasive .into_any() | |
| # erasure already claimed the wins (breaking up the largest single | |
| # function recovered 0.07%). The one remaining cut (fetch-on-demand | |
| # locales, ~55 KB gz) was declined to keep instant locale switching. | |
| # Gate stays at 1,850,000; future headroom is managed by this file's | |
| # rebaseline policy, not an optimization backlog. | |
| # 2026-10-01: owner-requested 20% increase for the Mermaid work. | |
| WASM_GZ_LIMIT: "2406000" # ~2.29 MiB, up from 2,005,000 B | |
| # Soft regression budget — a no-op-change PR that adds > 5% to the | |
| # bundle (without crossing the hard limit) gets a warning so a | |
| # quiet drift can be caught before it eats the headroom. | |
| WASM_GZ_SOFT_DELTA_PCT: "5" | |
| jobs: | |
| bundle-size: | |
| name: WASM bundle size gate | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust (stable + wasm32) | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: wasm32-unknown-unknown | |
| - name: Cache cargo | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: | | |
| . -> target | |
| frontend -> target | |
| shared-key: bundle-size | |
| # Pinned: `version: latest` resolved to trunk 0.19.1 on one runner and | |
| # 0.21.14 on another ten minutes apart (2026-09-26). 0.19.1 ignores | |
| # index.html's data-wasm-opt-params, so its wasm-opt 116 rejected the | |
| # bulk-memory ops rustc now emits for wasm32. 0.21.14 matches local dev. | |
| - name: Install trunk | |
| uses: taiki-e/install-action@5488ac5a951645ce95062214902ac4b6bc1a1037 # v2 | |
| with: | |
| tool: trunk@0.21.14 | |
| # Trunk downloads the wasm-bindgen version pinned in frontend/Cargo.lock. | |
| - name: Build frontend (release) | |
| working-directory: frontend | |
| # Size-optimizing profile overrides, applied here (not in | |
| # frontend/Cargo.toml [profile.release]) so local dev / e2e builds | |
| # stay fast. These MUST match the Dockerfile Stage 2 build so the | |
| # gate measures exactly what ships. wasm-opt=z still runs post-link | |
| # via index.html's data-wasm-opt directive. | |
| env: | |
| CARGO_PROFILE_RELEASE_OPT_LEVEL: z | |
| CARGO_PROFILE_RELEASE_LTO: fat | |
| CARGO_PROFILE_RELEASE_CODEGEN_UNITS: "1" | |
| CARGO_PROFILE_RELEASE_STRIP: "true" | |
| CARGO_PROFILE_RELEASE_PANIC: abort | |
| run: trunk build --release | |
| - name: Measure WASM bundle | |
| id: measure | |
| working-directory: frontend/dist | |
| run: | | |
| set -euo pipefail | |
| WASM=$(ls *_bg.wasm 2>/dev/null | head -1) | |
| if [ -z "$WASM" ]; then | |
| echo "::error::No *_bg.wasm produced in frontend/dist/" | |
| ls -la | |
| exit 1 | |
| fi | |
| RAW=$(stat -c%s "$WASM") | |
| GZ=$(gzip -9 -c "$WASM" | wc -c) | |
| echo "wasm=$WASM" | tee -a "$GITHUB_OUTPUT" | |
| echo "raw=$RAW" | tee -a "$GITHUB_OUTPUT" | |
| echo "gz=$GZ" | tee -a "$GITHUB_OUTPUT" | |
| { | |
| echo "## WASM bundle size" | |
| echo "" | |
| echo "| metric | bytes | human |" | |
| echo "|---|---|---|" | |
| printf "| raw | %s | %s |\n" "$RAW" "$(numfmt --to=iec --suffix=B "$RAW")" | |
| printf "| gzip -9 | %s | %s |\n" "$GZ" "$(numfmt --to=iec --suffix=B "$GZ")" | |
| printf "| limit | %s | %s |\n" "${WASM_GZ_LIMIT}" "$(numfmt --to=iec --suffix=B "${WASM_GZ_LIMIT}")" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Gate on threshold | |
| env: | |
| GZ: ${{ steps.measure.outputs.gz }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$GZ" -gt "$WASM_GZ_LIMIT" ]; then | |
| echo "::error::WASM bundle ${GZ} bytes > limit ${WASM_GZ_LIMIT} bytes (gzipped)." | |
| echo "See design/performance-budgets.md → 'Bundle size'." | |
| exit 1 | |
| fi | |
| echo "::notice::WASM bundle within budget: ${GZ} / ${WASM_GZ_LIMIT} (gz)." |