build: run the project on Bun 1.4.3 #299

Merged
nessar merged 7 commits from feature/bun-migration into develop 2026-10-17 18:28:43 +02:00
Owner

Moves project-owned JavaScript onto stable Bun 1.4.3 in development, tests, CI and the container, following ADR 0009 and the decisions recorded during the #289 verification.

Closes #289
Closes #291
Closes #292
Refs #290: native bun lint/bun fmt are canary-only, so ESLint and Prettier stay, run by Bun, until a stable release ships them.
Refs #293: the final gate is completed by this PR's live checks; the migration stays open with #290.

Decisions taken during #289

  • Version. Stable Bun 1.4.3 everywhere (packageManager, CI installer with pinned SHA-256s, digest-pinned oven/bun:1.4.3-alpine).
  • Server. Angular's server build relies on Node module.register loader hooks that Bun ignores. Every route is client-rendered, so Angular now builds client-only and a small Bun.serve server replaces Express and @angular/ssr.
  • Coverage. bun test collects line coverage only. HTML and Cobertura are generated from lcov, and branch and function coverage are shown as "not collected" rather than 100%.
  • Benchmark memory. JavaScriptCore has no heap flag, so the benchmark job uses a --memory=3g container limit.

Changes

  • Tests (#291)
    • bun test replaces Vitest, Jest, Nx and Vite.
    • A preload compiles components through Angular's JIT transform with inlined templates. It also sets up jsdom, TestBed and zoneless change detection.
    • src/testing/vitest-compat.ts covers the Vitest APIs that bun:test lacks.
    • Test files run isolated, and the real-worker specs spawn the running Bun.
    • The checkpoint-cancellation test is now deterministic.
  • Server and container (#292)
    • src/server.ts:
      • serves hashed assets with a one-year cache;
      • revalidates index.html;
      • falls back to index.html for client routes;
      • answers 404 for missing assets;
      • answers 400 for traversal or malformed paths and 405 for other methods.
    • It has 33 HTTP tests, including raw-path traversal.
    • The Docker image contains no Node, and its health checks honor PORT.
  • Development and checks (#290)
    • bunfig.toml sets [run] bun = true, so ng, ESLint and Prettier never fall back to an installed Node.
    • bun run typecheck uses bun check for the app and spec projects. TypeScript 6 stays for Angular.
  • CI (#293)
    • scripts/install-bun.sh installs the checksum-verified release, with no npm.
    • Project steps run in a job shell without Node on PATH. Node stays only for the checkout and upload-artifact JS actions.
    • Policy, publication and the required aggregation are unchanged.

Verification

  • Local, with Node unavailable:
    • frozen install;
    • typecheck, lint and format check;
    • 750/750 functional tests, plus the coverage run and its reports;
    • the policy and image regression scripts;
    • the production build and server probes;
    • the benchmark: 6/6 within budget;
    • a Docker build that reaches healthy.
  • Real Gitea runner engine (gitea-runner exec 5.1.0), locally: the validate, build, test and benchmark jobs pass with the custom shell; node is absent from project steps, and the JavaScript actions still work.
  • Review: an independent Opus review checked the server traversal handling, the installer checksums for all four platforms, and the spec diffs (no weakened assertions). Its findings are fixed in dfe6d28 and 282d9c6.
  • Still needed: live CI on this PR, covering the custom shell on the instance runner, the per-job Bun download, the images job with credentials, and the benchmark margin.

Known limits

  • The images job keeps Alpine's nodejs on PATH for the checkout action. The project command runs Bun by absolute path.
  • src/test-setup.ts deep-imports Analog's internal jitTransform. It is marked as a shortcut.

🤖 Generated with Claude Code

Moves project-owned JavaScript onto stable **Bun 1.4.3** in development, tests, CI and the container, following ADR 0009 and the decisions recorded during the #289 verification. Closes #289 Closes #291 Closes #292 Refs #290: native `bun lint`/`bun fmt` are canary-only, so ESLint and Prettier stay, run by Bun, until a stable release ships them. Refs #293: the final gate is completed by this PR's live checks; the migration stays open with #290. ## Decisions taken during #289 - **Version.** Stable Bun 1.4.3 everywhere (`packageManager`, CI installer with pinned SHA-256s, digest-pinned `oven/bun:1.4.3-alpine`). - **Server.** Angular's server build relies on Node `module.register` loader hooks that Bun ignores. Every route is client-rendered, so Angular now builds client-only and a small `Bun.serve` server replaces Express and `@angular/ssr`. - **Coverage.** `bun test` collects line coverage only. HTML and Cobertura are generated from lcov, and branch and function coverage are shown as "not collected" rather than 100%. - **Benchmark memory.** JavaScriptCore has no heap flag, so the benchmark job uses a `--memory=3g` container limit. ## Changes - **Tests (#291)** - `bun test` replaces Vitest, Jest, Nx and Vite. - A preload compiles components through Angular's JIT transform with inlined templates. It also sets up jsdom, TestBed and zoneless change detection. - `src/testing/vitest-compat.ts` covers the Vitest APIs that `bun:test` lacks. - Test files run isolated, and the real-worker specs spawn the running Bun. - The checkpoint-cancellation test is now deterministic. - **Server and container (#292)** - `src/server.ts`: - serves hashed assets with a one-year cache; - revalidates `index.html`; - falls back to `index.html` for client routes; - answers 404 for missing assets; - answers 400 for traversal or malformed paths and 405 for other methods. - It has 33 HTTP tests, including raw-path traversal. - The Docker image contains no Node, and its health checks honor `PORT`. - **Development and checks (#290)** - `bunfig.toml` sets `[run] bun = true`, so `ng`, ESLint and Prettier never fall back to an installed Node. - `bun run typecheck` uses `bun check` for the app and spec projects. TypeScript 6 stays for Angular. - **CI (#293)** - `scripts/install-bun.sh` installs the checksum-verified release, with no npm. - Project steps run in a job shell without Node on `PATH`. Node stays only for the checkout and upload-artifact JS actions. - Policy, publication and the required aggregation are unchanged. ## Verification - **Local, with Node unavailable:** - frozen install; - `typecheck`, lint and format check; - 750/750 functional tests, plus the coverage run and its reports; - the policy and image regression scripts; - the production build and server probes; - the benchmark: 6/6 within budget; - a Docker build that reaches healthy. - **Real Gitea runner engine (`gitea-runner exec` 5.1.0), locally:** the validate, build, test and benchmark jobs pass with the custom shell; `node` is absent from project steps, and the JavaScript actions still work. - **Review:** an independent Opus review checked the server traversal handling, the installer checksums for all four platforms, and the spec diffs (no weakened assertions). Its findings are fixed in `dfe6d28` and `282d9c6`. - **Still needed:** live CI on this PR, covering the custom shell on the instance runner, the per-job Bun download, the `images` job with credentials, and the benchmark margin. ## Known limits - The `images` job keeps Alpine's `nodejs` on `PATH` for the checkout action. The project command runs Bun by absolute path. - `src/test-setup.ts` deep-imports Analog's internal `jitTransform`. It is marked as a shortcut. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
nessar added 7 commits 2026-10-17 16:10:52 +02:00
Record the proposed decision to run project-owned JavaScript under Bun
with its native test runner, linter, formatter, type checker and HTTP
server, keeping Angular's standard build pipeline, plus the development
spec for the migration tickets.

Refs #289

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stable Bun 1.4.3 runs installs, the development server, standalone type
checks, the native test runner and a Bun.serve static server. Native
lint/fmt are canary-only, and Angular's server build needs Node loader
hooks Bun does not apply, so the spec now keeps ESLint/Prettier until a
stable release, builds Angular client-only behind a Bun static server,
converts line coverage from lcov, and replaces the heap cap with a
container memory limit.

Refs #289

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace Vitest with bun test across the whole suite. A preload compiles
components through Angular's JIT transform with inlined templates, sets
up jsdom, TestBed and zoneless change detection, and a small shim covers
the Vitest APIs bun:test lacks. Files run isolated, real-worker specs
spawn the running Bun, and line coverage from lcov is converted to the
existing HTML and Cobertura reports. The CI benchmark replaces its heap
cap with a container memory limit. Vitest, Jest, Nx and their Vite
configuration are removed.

Refs #291

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Angular's server build needs Node loader hooks that Bun does not apply,
and every route is client-rendered, so Angular now builds a client-only
bundle and a small Bun.serve server delivers it: hashed assets with the
one-year cache, index.html revalidated, extension-less routes falling
back to index.html, missing assets 404, traversal and malformed paths
rejected, and other methods 405. Express, @angular/ssr and the unused
hydration provider are removed. Both Docker stages use the pinned
oven/bun:1.4.3-alpine image without Node, and the health checks use
Bun's fetch.

Refs #292

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pin Bun 1.4.3 with packageManager, and force every bun run script onto
the Bun runtime through bunfig so ng, ESLint and Prettier never fall
back to an installed Node. Type checking uses bun check for the
application and test projects, next to the Angular build.

CI jobs install the pinned release from a checksum-verified download
instead of npm and run project steps in a shell without Node on PATH,
which stays available only for the checkout and upload actions. The
image test's fake docker runs on Bun.

Refs #290, #293

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cancelled stage takes about a millisecond, so under load the worker
could finish it before the cancel message arrived and report it as
completed. The real-worker harness now holds the worker after reporting
that stage until the cancel is delivered, keeping every assertion.

Refs #291

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix: report line-only coverage honestly and tighten Bun test helpers
CI / policy (push) Successful in 7s
CI / validate (push) Successful in 41s
CI / build (push) Successful in 36s
CI / policy (pull_request) Successful in 10s
CI / validate (pull_request) Successful in 32s
CI / security (push) Successful in 1m3s
CI / test (push) Successful in 3m3s
CI / build (pull_request) Successful in 23s
CI / security (pull_request) Successful in 57s
CI / test (pull_request) Successful in 3m25s
CI / benchmark (push) Successful in 5m19s
CI / benchmark (pull_request) Successful in 4m48s
CI / images (push) Successful in 1m20s
CI / required (push) Successful in 3s
CI / images (pull_request) Successful in 54s
CI / required (pull_request) Successful in 1s
282d9c6787
The generated HTML and Cobertura reports no longer show unmeasured
branch and function coverage as 100%. Poll and waitFor deadlines use
performance.now so frozen dates cannot make them loop forever, the
malformed-configuration test covers undefined again next to the empty
array, compose health checks honor PORT, and the migration spec lists
only what is still open.

Refs #291, #292, #293

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nessar merged commit 85fc4561fd into develop 2026-10-17 18:28:43 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: nessar/vac-optimizer#299