Skip to content

Move the web parts from pnpm and Node to Bun - #18

Merged
firsttris merged 2 commits into
mainfrom
bun-migration
Nov 4, 2026
Merged

firsttris merged 2 commits into
mainfrom
bun-migration

Conversation

@firsttris

Copy link
Copy Markdown
Owner

Moves the web parts (web/ui, web/viewer, web/client-ui, web/e2e) from pnpm and Node to Bun: package manager, script runner and Playwright runner, following firsttris/workflows tech-stack.md ("Tooling") and the haul and windfenster migrations.

Changes

  • Workspace: workspaces in package.json (from pnpm-workspace.yaml), packageManager: bun@1.4.4. bun.lock was migrated from pnpm-lock.yaml and keeps the same versions: the 245 package@version entries match the pnpm lockfile exactly; only pnpm itself (packageManagerDependencies) is gone. bunfig.toml: linker = "isolated" (pnpm's layout) and minimumReleaseAge = 86400 (pnpm 12's default). No build scripts are blocked (bun pm untrusted: 0), so no trustedDependencies. pnpm files deleted.
  • Scripts: bun run --filter …, bun run --filter '*' for build/typecheck, bun --bun vite in the apps, bun --bun vitest, bun --bun playwright test in web/e2e (already "type": "module"). Playwright's web servers run bun --bun vite preview in the apps' folders (cwd). scripts/screenshots.sh stays bash; its pnpm/node calls are now bun.
  • Tauri: beforeDevCommand/beforeBuildCommand use bun run --filter; packaging/appimage.sh runs bunx tauri build, build.sh installs with bun.
  • CI: oven-sh/setup-bun (pinned to v2.2.0, bun-version-file: package.json) and bun install --frozen-lockfile in ci.yml (desktop fallback, web-lint, web-unit, web-e2e) and release.yml; no setup-node or pnpm/action-setup any more. Playwright cache key on bun.lock. The screenshots workflow (shared firsttris/workflows) installs the Bun of packageManager with npm install --global "bun@$(node -p …)" in the Playwright image, lockfile: bun.lock. scripts/ci-changes.sh watches bun.lock and bunfig.toml.
  • Dev image: dev/Containerfile takes bun from oven/bun:1.4.4 instead of nodejs22 pnpm; the GPU runner's PNPM_HOME becomes BUN_INSTALL_CACHE_DIR. Nothing else in the runner changes.
  • Renovate: a regex manager for packageManager and a "Bun" group with the dev image's oven/bun.
  • Docs: CLAUDE.md's checks, scripts/check.sh, docs (development, testing, modules, gpu-runner), README, apps/desktop README.

Checks (local)

  • bun install --frozen-lockfile: no changes
  • bun run check (Biome): 93 files, clean
  • bun run --filter '*' typecheck: all 4 packages pass
  • bun run test (Vitest on Bun): 23 files, 203 tests passed, the same counts as pnpm test on Node before; coverage on Bun passes its thresholds (lines 96.91 %, branches 90.47 %; Node: 90.9 %)
  • bun run --filter @fernsicht/client-ui build: passes; the client-ui and viewer builds with bun --bun vite build are identical to Node's
  • Playwright --list: 42 tests in 2 files, the same as with pnpm/Node; a full bun run test:e2e (building and serving both apps): 42 passed
  • bun run screenshots: ran through (9 pictures, not committed)

Not checked here

  • The Rust workspace and the desktop app's cargo jobs were not built; no GPU tests.
  • The dev and runner images were not built (the Containers workflow builds them on this PR).
  • shellcheck and mkdocs build --strict are not installed here (CI's docs build runs them).
  • In one of nine full Vitest runs on Bun, a component test (session-view.test.tsx) failed once while the machine was under load from other processes; it did not happen again in the other runs, or in eight runs of that file alone.

Generated by Claude Code

Bun is the package manager, script runner and Playwright runner of the web
workspace, as firsttris/workflows tech-stack.md ("Tooling") asks and as haul
and windfenster did:

- package.json: `workspaces` (from pnpm-workspace.yaml), `packageManager:
  bun@1.4.4`; bun.lock migrated from pnpm-lock.yaml with the same versions
  (only pnpm itself is gone); bunfig.toml keeps pnpm's isolated layout and
  its one-day minimum release age.
- Scripts: `bun run --filter`, `bun --bun vite` and `bun --bun vitest`, and
  `bun --bun playwright test` in web/e2e, whose web servers run
  `bun --bun vite preview` in the apps' folders. Under Bun the Vite builds
  are byte for byte the ones Node made. screenshots.sh stays bash with bun
  in place of pnpm and node.
- Tauri's beforeDevCommand/beforeBuildCommand and the packaging scripts
  (bunx tauri) use Bun.
- CI and release: setup-bun with bun-version-file, `bun install
  --frozen-lockfile`; no setup-node and pnpm/action-setup. The screenshots
  job installs the Bun of packageManager with npm in the Playwright image.
  ci-changes.sh watches bun.lock and bunfig.toml.
- The dev image takes bun from oven/bun instead of nodejs22 and pnpm; the
  runner's package cache moves to BUN_INSTALL_CACHE_DIR.
- Renovate: Bun (packageManager and the dev image) in one group.
- CLAUDE.md's checks, scripts/check.sh, the docs and READMEs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y3rdfbWb1xDUdPRng7TX9Z

Copy link
Copy Markdown
Owner Author

TDD review: one finding

Renovate: the Bun of packageManager lands in the monthly automerge group, not in the "Bun" group

File: .github/renovate.json5 (custom manager at line 16–25, package rule at line 153–166)

Renovate's own bun manager already reads "packageManager": "bun@1.4.4" from package.json, as a dependency named bun (datasource npm). The "Bun" rule matches only docker.io/oven/bun, oven/bun and oven-sh/bun (the name the extra regex manager gives the same string). So bun falls into the shared minor/patch group, which merges itself: CI's Bun would move without the dev image's oven/bun (and the regex manager would bump the very same line a second time in renovate/bun). That is the split the rule's comment says it prevents.

Test: Renovate run locally against the branch with both versions set back to 1.3.0 (so there is something to update):

sed -i 's/"bun@1.4.4"/"bun@1.3.0"/' package.json
sed -i 's#oven/bun:1.4.4#oven/bun:1.3.0#' dev/Containerfile
git commit -qam tmp
LOG_LEVEL=debug LOG_FORMAT=json bunx --bun --package renovate renovate --platform=local --dry-run=lookup

Red output (extracted deps and Renovate's own warning):

bun        package.json       bun 1.3.0                → 1.4.4  branch renovate/minor-patch
dockerfile dev/Containerfile  docker.io/oven/bun 1.3.0 → 1.4.4  branch renovate/bun

"Found sourceUrl with multiple branches that should probably be combined into a group"
  sourceUrl: https://github.com/oven-sh/bun
  branches: {"renovate/minor-patch": "bun", "renovate/bun": "docker.io/oven/bun"}

(The regex dep oven-sh/bun could not be looked up here, the GitHub GraphQL API is blocked in this session; on GitHub it would add a second update of the same line in renovate/bun.)

Fix: drop the redundant regex manager and put bun into the Bun group's matchPackageNames. Commit follows on this branch.

Checked and discarded (no red test)

  • bunx tauri build (appimage.sh): uses the lockfile's @tauri-apps/cli 2.12.4 from the root node_modules/.bin (a fake tauri there was the one run from apps/desktop); also runs with no node in PATH.
  • bun run --filter … in tauri's before*Command, the desktop CI job (working directory apps/desktop, no package.json there) and root typecheck: finds the workspace, a failing build/type error exits 1 and stops the && chain.
  • Release workflow: no node -p or other Node use left; appimage.sh works without Node.
  • GPU runners/dev image: the GPU jobs run no Bun or Node (cargo only); nothing in the repo calls node outside the Playwright image (screenshots.yml, which has Node); the node -p expression yields bun@1.4.4.
  • Coverage: branch threshold is 85 %, Bun gives 90.47 %; 6 runs of test:coverage on 2 cores (taskset) all green, session-view included, plus 5 plain bun run test runs.
  • Browser E2E (bun --bun playwright test, 42 tests) and bun run screenshots (vite preview on Bun, bun -e fetch, bun web/e2e/screenshots.mjs) run green locally.
  • bunx --package renovate renovate-config-validator works as the comment says.

Generated by Claude Code

Renovate's bun manager reads "packageManager": "bun@…" from package.json
itself, as the dependency "bun" (npm datasource). The Bun rule matched
only the regex manager's name for the same line (oven-sh/bun), so "bun"
went into the shared monthly group, which merges itself, and CI's Bun
would have moved without the dev image's oven/bun. A local run
(renovate --platform=local --dry-run=lookup, both pinned back to 1.3.0)
put bun in renovate/minor-patch and docker.io/oven/bun in renovate/bun
and warned that one sourceUrl spans two branches; with this change both
land in renovate/bun.

The regex manager is dropped: it only extracted the same line a second
time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y3rdfbWb1xDUdPRng7TX9Z

Copy link
Copy Markdown
Owner Author

Fix pushed: 51a3c2f (Renovate: the Bun of packageManager in the Bun group). Green test: the same local Renovate run now puts bun (package.json) and docker.io/oven/bun (dev/Containerfile) both in renovate/bun, without the "multiple branches" warning; renovate-config-validator passes. Checks on the branch: bun run check, bun run --filter '*' typecheck, bun run test (203 passed), client-ui build all green.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

TDD-Review abgeschlossen: 1 belegtes Finding (Renovate trennte bun aus packageManager von oven/bun) gefixt in 51a3c2f. CI grün: Web, Rust, Desktop, Fuzz, Images. Merge per Squash.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants