Verify Bun and Angular compatibility #289

Closed
opened 2026-10-17 02:35:36 +02:00 by nessar · 1 comment
Owner

Migration scope

The agreed target is Bun as the runtime for project-owned JavaScript in development, CI, and production, plus its native test runner, linter, formatter, standalone type checker, and HTTP server. Bun adoption is required even without measured performance gains. Retain Angular and its standard compiler/build pipeline, using TypeScript 6 for Angular compilation alongside Bun’s TypeScript 7-based standalone checker. The planner remains in the browser and current client rendering stays unchanged. Preserve tests, coverage, lint rules, behavior, and benchmark budgets. No compatibility proof exists yet; Bun 1.4.3 is a candidate, not a verified selection. Native-tool limitations and CI-platform exceptions must be resolved explicitly rather than hidden by a Node fallback. The architecture record is still proposed.

What to build

Give the maintainer a verified Bun release and a reproducible
path to the agreed native toolchain before committing to the migration. Establish
that Angular can retain its standard build pipeline while Bun runs project-owned
JavaScript, and expose any concrete incompatibility early.

Acceptance criteria

  • Evaluate Bun 1.4.3 as the initial candidate and select an exact release only
    after verifying the required runtime, test, lint, format, type-check, and
    HTTP-server capabilities. Record the versions and reproduction steps.
  • From a clean checkout, demonstrate a frozen install and an Angular
    production build under Bun, with Node unavailable to project commands.
    Identify spawned executables and prove which runtime executes them.
  • Demonstrate representative native Bun tests covering an Angular component
    with external resources, TestBed setup, date control, global mock cleanup,
    file isolation, and the existing real-worker testing approach. Record the
    minimum required Angular test-compilation integration.
  • Compare the native linter and formatter with the current rules, including
    deprecated API checks, unused-name exceptions, configured severities, and
    Angular-template formatting. Demonstrate that representative violations
    still fail the intended check.
  • Demonstrate standalone Bun type checking alongside Angular's supported
    TypeScript 6 compiler, including an application type error, a test type
    error, and an Angular template error detected by the appropriate command.
  • Establish coverage capability and reporting parity against the current
    text, HTML, and Cobertura outputs and frozen-baseline exclusions. Identify
    unsupported metrics or formats explicitly; accepting reduced reporting is
    not an agreed fallback.
  • Verify Angular's web request-handler contract can integrate with Bun's
    server without changing the current client-rendered route configuration.
  • Identify actual Node requirements imposed by third-party Gitea actions
    separately from project commands. Any exception or infrastructure change
    beyond the agreed migration remains unresolved until explicitly decided.
  • Record successful probes and concrete blockers in this issue and development documentation.
    Downstream adoption is blocked until a verified approach meets the agreed
    capabilities; do not silently substitute Node or weaken checks.
  • Keep probes disposable. Once implementation begins, use one scoped
    feature/* integration branch from current origin/develop, targeting
    develop. Tickets 02–05 share that branch, and ticket 05 owns the final
    integration gate. Do not add dual toolchains solely to make batches green.

Blocked by

None — can start immediately.

## Migration scope The agreed target is Bun as the runtime for project-owned JavaScript in development, CI, and production, plus its native test runner, linter, formatter, standalone type checker, and HTTP server. Bun adoption is required even without measured performance gains. Retain Angular and its standard compiler/build pipeline, using TypeScript 6 for Angular compilation alongside Bun’s TypeScript 7-based standalone checker. The planner remains in the browser and current client rendering stays unchanged. Preserve tests, coverage, lint rules, behavior, and benchmark budgets. No compatibility proof exists yet; Bun 1.4.3 is a candidate, not a verified selection. Native-tool limitations and CI-platform exceptions must be resolved explicitly rather than hidden by a Node fallback. The architecture record is still proposed. ## What to build Give the maintainer a verified Bun release and a reproducible path to the agreed native toolchain before committing to the migration. Establish that Angular can retain its standard build pipeline while Bun runs project-owned JavaScript, and expose any concrete incompatibility early. ## Acceptance criteria - [ ] Evaluate Bun 1.4.3 as the initial candidate and select an exact release only after verifying the required runtime, test, lint, format, type-check, and HTTP-server capabilities. Record the versions and reproduction steps. - [ ] From a clean checkout, demonstrate a frozen install and an Angular production build under Bun, with Node unavailable to project commands. Identify spawned executables and prove which runtime executes them. - [ ] Demonstrate representative native Bun tests covering an Angular component with external resources, TestBed setup, date control, global mock cleanup, file isolation, and the existing real-worker testing approach. Record the minimum required Angular test-compilation integration. - [ ] Compare the native linter and formatter with the current rules, including deprecated API checks, unused-name exceptions, configured severities, and Angular-template formatting. Demonstrate that representative violations still fail the intended check. - [ ] Demonstrate standalone Bun type checking alongside Angular's supported TypeScript 6 compiler, including an application type error, a test type error, and an Angular template error detected by the appropriate command. - [ ] Establish coverage capability and reporting parity against the current text, HTML, and Cobertura outputs and frozen-baseline exclusions. Identify unsupported metrics or formats explicitly; accepting reduced reporting is not an agreed fallback. - [ ] Verify Angular's web request-handler contract can integrate with Bun's server without changing the current client-rendered route configuration. - [ ] Identify actual Node requirements imposed by third-party Gitea actions separately from project commands. Any exception or infrastructure change beyond the agreed migration remains unresolved until explicitly decided. - [ ] Record successful probes and concrete blockers in this issue and development documentation. Downstream adoption is blocked until a verified approach meets the agreed capabilities; do not silently substitute Node or weaken checks. - [ ] Keep probes disposable. Once implementation begins, use one scoped `feature/*` integration branch from current `origin/develop`, targeting `develop`. Tickets 02–05 share that branch, and ticket 05 owns the final integration gate. Do not add dual toolchains solely to make batches green. ## Blocked by None — can start immediately.
nessar added the ready-for-agent label 2026-10-17 02:35:36 +02:00
nessar added a new dependency 2026-10-17 02:35:38 +02:00
nessar added a new dependency 2026-10-17 02:35:38 +02:00
nessar added a new dependency 2026-10-17 02:35:38 +02:00
Author
Owner

Verification on stable Bun 1.4.3 (1.4.3+c6da4a4d3, SHA-256 verified), from a clean checkout. "Node unavailable" means only bun plus /usr/bin:/bin on PATH. Full results and decisions are in docs/bun-adoption.md → "Verification Results and Decisions (#289)" on feature/bun-migration.

Pass

  • bun install --frozen-lockfile: lockfile unchanged.
  • bun --bun x ng serve with Node unavailable: / and /benchmark load. --bun is required for every #!/usr/bin/env node binary; without it they run on Node whenever Node is on PATH.
  • bun check (app and spec tsconfigs) matches tsc 6 and catches app and test type errors. Template errors are caught only by the Angular build.
  • bun test: 715/716 functional tests pass with a preload and a Vitest-API shim, including real-worker specs with Node unavailable. The single failure is a malformed it.each row in planning-objectives.spec.ts. --parallel=4 takes about 64 s, the same as Vitest. --isolate/--parallel is required for per-file isolation.
  • The benchmark passes under bun test. The numbers are new Bun measurements, not comparable with Node.
  • Bun.serve passes route, asset, cache-header, 404 and traversal checks.
  • ESLint and Prettier run on Bun and still fail on injected violations.

Blockers and decisions (maintainer)

  • Lint/format: native bun lint and bun fmt exist only in canary (1.4.4-canary.1). Decision: pin stable 1.4.3 and keep ESLint/Prettier until a stable release ships them.
  • Production build: Angular's server/SSR build fails under Bun. Route extraction imports the server bundle via memory: URLs, which needs Node module.register hooks; Bun ignores them. Decision: build Angular client-only (every route is client-rendered today) and serve it with a small Bun.serve static server with SPA fallback. This gives up @angular/ssr.
  • Coverage: Bun emits only text and lcov, with line data. Decision: generate HTML and Cobertura from lcov with the istanbul report libraries, accepting the loss of branch and function coverage.
  • Heap cap: JSC has no --max-old-space-size. Decision: use a container memory limit on the CI benchmark job.

Platform constraints and smaller fixes

  • actions/checkout@v4 (node20) and actions/upload-artifact@v3 (node16) are JS actions, so the job container still needs node for the runner. Project commands won't use it.
  • scripts/ci-image.test.mjs generates its fake docker with a node shebang; switching it to bun passes. ci-policy.test.mjs already passes under Bun.
  • Found while probing: the current Express server answers 400 unless NG_ALLOWED_HOSTS is set, and the compose files set only PORT. The Bun static server removes this.
  • oven/bun:1.4.3-alpine exists (amd64 and arm64), and the client-only build works on musl.

Implementation continues on feature/bun-migration (#290–#293).

Verification on stable Bun **1.4.3** (`1.4.3+c6da4a4d3`, SHA-256 verified), from a clean checkout. "Node unavailable" means only `bun` plus `/usr/bin:/bin` on `PATH`. Full results and decisions are in `docs/bun-adoption.md` → "Verification Results and Decisions (#289)" on `feature/bun-migration`. **Pass** - `bun install --frozen-lockfile`: lockfile unchanged. - `bun --bun x ng serve` with Node unavailable: `/` and `/benchmark` load. `--bun` is required for every `#!/usr/bin/env node` binary; without it they run on Node whenever Node is on `PATH`. - `bun check` (app and spec tsconfigs) matches tsc 6 and catches app and test type errors. Template errors are caught only by the Angular build. - `bun test`: 715/716 functional tests pass with a preload and a Vitest-API shim, including real-worker specs with Node unavailable. The single failure is a malformed `it.each` row in `planning-objectives.spec.ts`. `--parallel=4` takes about 64 s, the same as Vitest. `--isolate`/`--parallel` is required for per-file isolation. - The benchmark passes under `bun test`. The numbers are new Bun measurements, not comparable with Node. - `Bun.serve` passes route, asset, cache-header, 404 and traversal checks. - ESLint and Prettier run on Bun and still fail on injected violations. **Blockers and decisions (maintainer)** - **Lint/format:** native `bun lint` and `bun fmt` exist only in canary (`1.4.4-canary.1`). Decision: pin stable 1.4.3 and keep ESLint/Prettier until a stable release ships them. - **Production build:** Angular's server/SSR build fails under Bun. Route extraction imports the server bundle via `memory:` URLs, which needs Node `module.register` hooks; Bun ignores them. Decision: build Angular client-only (every route is client-rendered today) and serve it with a small `Bun.serve` static server with SPA fallback. This gives up `@angular/ssr`. - **Coverage:** Bun emits only text and lcov, with line data. Decision: generate HTML and Cobertura from lcov with the istanbul report libraries, accepting the loss of branch and function coverage. - **Heap cap:** JSC has no `--max-old-space-size`. Decision: use a container memory limit on the CI benchmark job. **Platform constraints and smaller fixes** - `actions/checkout@v4` (node20) and `actions/upload-artifact@v3` (node16) are JS actions, so the job container still needs `node` for the runner. Project commands won't use it. - `scripts/ci-image.test.mjs` generates its fake `docker` with a `node` shebang; switching it to `bun` passes. `ci-policy.test.mjs` already passes under Bun. - Found while probing: the current Express server answers 400 unless `NG_ALLOWED_HOSTS` is set, and the compose files set only `PORT`. The Bun static server removes this. - `oven/bun:1.4.3-alpine` exists (amd64 and arm64), and the client-only build works on musl. Implementation continues on `feature/bun-migration` (#290–#293).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: nessar/vac-optimizer#289