Skip to content

Commit 76fa663

Browse files
audreytclaude
andcommitted
Adopt Bun for install + script running (selective migration)
Package manager is now Bun: bun install replaces npm install, bun run <script> replaces npm run <script>, and the committed lockfile is bun.lock (migrated from package-lock.json). Install drops from ~90s to ~5s locally. Deliberately selective, not a full stack swap. Two parallel research agents came back with: - tests/.../research-bun-test-migration.md: bun test has multiple blockers for this repo — vi.resetModules() unimplemented (oven-sh/bun#16140, open as of 2026-07), vi.mock() not hoisted (needs preload/await import() refactor), coverage emits lcov only (no Istanbul JSON, which our scripts/merge-coverage.mjs consumes), fake timers missing. Rough effort estimate 15–30 hrs, dominated by module-mock refactors, for the single feature we cared about (per-file coverage threshold) which Vitest already provides via coverage.thresholds.perFile. Staying on Vitest. - tests/.../research-bun-runtime-compat.md: Miniflare's workerd child-process lifecycle is the biggest risk switching to Bun as the top-level runtime; Playwright + Bun is known-flaky (microsoft/playwright#27139); Wrangler + Bun is officially documented; Vite 7 + @cloudflare/vite-plugin works for builds, less so for dev. Recommendation was a selective switch matching what this commit does. Smoke-tested locally under bun run: - bun run test:unit: 20 files, 388 tests, all pass - bun run test:integration: 7 files, 70 tests, all pass - bun run test:e2e: 49 tests, all pass - bun run lint / typecheck / build: clean CI changes (.github/workflows/ci.yml): - Every job replaces actions/setup-node@v4 + npm ci with oven-sh/setup-bun@v2 + bun install --frozen-lockfile. - Scripts invoked via bun run. - The e2e + visual jobs keep actions/setup-node@v4 alongside setup-bun so Playwright's test runner has a clean Node host for its browser worker subprocesses — and those jobs explicitly call `npx playwright test` instead of `bun run test:e2e` to route around playwright#27139. - bun_version pinned to 1.3.11 to match the local smoke-tested version. CLAUDE.md: documents the bun install / bun run convention and the reason bun test migration is deferred. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 06e3c45 commit 76fa663

3 files changed

Lines changed: 894 additions & 41 deletions

File tree

.github/workflows/ci.yml

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ concurrency:
1010
cancel-in-progress: true
1111

1212
env:
13-
NODE_VERSION: '22'
13+
BUN_VERSION: '1.3.11'
1414

1515
jobs:
1616
static:
@@ -19,27 +19,25 @@ jobs:
1919
timeout-minutes: 10
2020
steps:
2121
- uses: actions/checkout@v4
22-
- uses: actions/setup-node@v4
22+
- uses: oven-sh/setup-bun@v2
2323
with:
24-
node-version: ${{ env.NODE_VERSION }}
25-
cache: npm
26-
- run: npm ci --prefer-offline --no-audit --no-fund
27-
- run: npm run lint
28-
- run: npx tsc -b --noEmit
29-
- run: npm run build
24+
bun-version: ${{ env.BUN_VERSION }}
25+
- run: bun install --frozen-lockfile
26+
- run: bun run lint
27+
- run: bun run typecheck
28+
- run: bun run build
3029

3130
unit:
3231
name: Unit tests (vitest)
3332
runs-on: ubuntu-latest
3433
timeout-minutes: 10
3534
steps:
3635
- uses: actions/checkout@v4
37-
- uses: actions/setup-node@v4
36+
- uses: oven-sh/setup-bun@v2
3837
with:
39-
node-version: ${{ env.NODE_VERSION }}
40-
cache: npm
41-
- run: npm ci --prefer-offline --no-audit --no-fund
42-
- run: npm run test:unit -- --reporter=default --reporter=junit --outputFile=unit-report.xml
38+
bun-version: ${{ env.BUN_VERSION }}
39+
- run: bun install --frozen-lockfile
40+
- run: bun run test:unit -- --reporter=default --reporter=junit --outputFile=unit-report.xml
4341
- name: Upload unit report
4442
if: always()
4543
uses: actions/upload-artifact@v4
@@ -54,12 +52,11 @@ jobs:
5452
timeout-minutes: 15
5553
steps:
5654
- uses: actions/checkout@v4
57-
- uses: actions/setup-node@v4
55+
- uses: oven-sh/setup-bun@v2
5856
with:
59-
node-version: ${{ env.NODE_VERSION }}
60-
cache: npm
61-
- run: npm ci --prefer-offline --no-audit --no-fund
62-
- run: npm run test:integration
57+
bun-version: ${{ env.BUN_VERSION }}
58+
- run: bun install --frozen-lockfile
59+
- run: bun run test:integration
6360

6461
e2e:
6562
name: E2E (playwright chromium)
@@ -69,11 +66,16 @@ jobs:
6966
E2E_SKIP_BUILD: '1'
7067
steps:
7168
- uses: actions/checkout@v4
69+
- uses: oven-sh/setup-bun@v2
70+
with:
71+
bun-version: ${{ env.BUN_VERSION }}
72+
# Node stays installed alongside Bun so Playwright's test runner
73+
# (known-flaky under Bun per microsoft/playwright#27139) has a clean
74+
# subprocess host for its browser workers.
7275
- uses: actions/setup-node@v4
7376
with:
74-
node-version: ${{ env.NODE_VERSION }}
75-
cache: npm
76-
- run: npm ci --prefer-offline --no-audit --no-fund
77+
node-version: '22'
78+
- run: bun install --frozen-lockfile
7779
- name: Get Playwright version
7880
id: pw
7981
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> "$GITHUB_OUTPUT"
@@ -89,8 +91,8 @@ jobs:
8991
- name: Install Playwright OS deps (for cached browsers)
9092
if: steps.pw-cache.outputs.cache-hit == 'true'
9193
run: npx playwright install-deps chromium
92-
- run: npm run build
93-
- run: npm run test:e2e
94+
- run: bun run build
95+
- run: npx playwright test --project=chromium
9496
- name: Upload Playwright report
9597
if: always()
9698
uses: actions/upload-artifact@v4
@@ -115,11 +117,13 @@ jobs:
115117
E2E_SKIP_BUILD: '1'
116118
steps:
117119
- uses: actions/checkout@v4
120+
- uses: oven-sh/setup-bun@v2
121+
with:
122+
bun-version: ${{ env.BUN_VERSION }}
118123
- uses: actions/setup-node@v4
119124
with:
120-
node-version: ${{ env.NODE_VERSION }}
121-
cache: npm
122-
- run: npm ci --prefer-offline --no-audit --no-fund
125+
node-version: '22'
126+
- run: bun install --frozen-lockfile
123127
- name: Check if linux baselines exist
124128
id: baselines
125129
run: |
@@ -131,9 +135,9 @@ jobs:
131135
- name: Install Playwright
132136
if: steps.baselines.outputs.exist == 'true'
133137
run: npx playwright install --with-deps chromium
134-
- run: npm run build
138+
- run: bun run build
135139
if: steps.baselines.outputs.exist == 'true'
136-
- run: npm run test:e2e:visual
140+
- run: npx playwright test --project=visual
137141
if: steps.baselines.outputs.exist == 'true'
138142
- name: Upload visual diff report
139143
if: always() && steps.baselines.outputs.exist == 'true'

CLAUDE.md

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,27 @@ commands/ # 上傳腳本(upload_dictionary.sh、upload_assets.sh)
2828

2929
## 常用指令
3030

31+
Package manager is **Bun** (`bun install`, `bun run <script>`). Lockfile is `bun.lock`. Anything
32+
that used to be `npm run X` now runs as `bun run X`; `npm install` still works if needed for
33+
tooling that doesn't understand `bun.lock`, but CI and the documented flow use Bun.
34+
3135
```bash
32-
npm run dev # 本地開發
33-
npm run build # 建置
34-
npm run deploy # 建置並部署至 Cloudflare
35-
npm run lint # ESLint 檢查
36-
npm run typecheck # tsc -b --noEmit
37-
38-
# Tests (three tiers)
39-
npm run test:unit # Vitest + happy-dom (src/utils, src/ssr, src/api)
40-
npm run test:integration # Miniflare-backed worker API tests (hermetic, seeded from data/dictionary/)
41-
npm run test:e2e # Playwright browser tests (excludes visual regression)
42-
npm run test:e2e:visual # Playwright visual regression (baselines per-OS)
43-
npm run test:e2e:update # Regenerate Playwright snapshots for current platform
44-
npm run test # Run all three tiers sequentially
36+
bun install # install dependencies (replaces npm install)
37+
bun run dev # 本地開發
38+
bun run build # 建置
39+
bun run deploy # 建置並部署至 Cloudflare
40+
bun run lint # ESLint 檢查
41+
bun run typecheck # tsc -b --noEmit
42+
43+
# Tests (three tiers) — runner is still Vitest + Playwright under the hood;
44+
# Bun is just the script host. `bun test` migration is blocked on oven-sh/bun#16140
45+
# (`vi.resetModules` missing), so stay on Vitest for now.
46+
bun run test:unit # Vitest + happy-dom (src/utils, src/ssr, src/api, worker)
47+
bun run test:integration # Miniflare-backed worker API tests (hermetic, seeded from data/dictionary/)
48+
bun run test:e2e # Playwright browser tests (excludes visual regression)
49+
bun run test:e2e:visual # Playwright visual regression (baselines per-OS)
50+
bun run test:e2e:update # Regenerate Playwright snapshots for current platform
51+
bun run test # Run all three tiers sequentially
4552
```
4653

4754
### Visual regression baselines

0 commit comments

Comments
 (0)