chore(deps): migrate web/ package management from npm to bun (#11262)

This commit is contained in:
Raunak Bhagat authored and GitHub committed 2026-05-21 03:56:14 +00:00
1 parent b21fcce851
commit 9fff80bc10
19 files changed
+3035 -18477

No files matched your search

+5 -3
View File
@@ -25,8 +25,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
unzip \
wget \
zsh \
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y nodejs \
&& install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
@@ -41,6 +39,10 @@ RUN ln -sf "$(which fdfind)" /usr/local/bin/fd
# Install uv (Python package manager)
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
# Install bun (JavaScript package manager)
COPY --from=oven/bun:1@sha256:e10577f0db68676a7024391c6e5cb4b879ebd17188ab750cf10024a6d700e5c4 /usr/local/bin/bun /usr/local/bin/bun
RUN ln -s /usr/local/bin/bun /usr/local/bin/bunx
# Create non-root dev user with passwordless sudo
RUN useradd -m -s /bin/zsh dev && \
echo "dev ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/dev && \
@@ -55,7 +57,7 @@ WORKDIR /workspace
# Install Claude Code
ARG CLAUDE_CODE_VERSION=latest
RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}
RUN BUN_INSTALL=/usr/local bun install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}
# Configure zsh — source the repo-local zshrc so shell customization
# doesn't require an image rebuild.
+2 -1
View File
@@ -22,7 +22,8 @@ cache-size=1000
# Domains whose resolved IPs should be added to the firewall allowlist.
# Keep in sync with ALLOWED_DOMAINS in init-firewall.sh.
ipset=/github.com/api.github.com/allowed-domains
ipset=/registry.npmjs.org/deb.nodesource.com/allowed-domains
ipset=/registry.npmjs.org/allowed-domains
ipset=/bun.sh/objects.githubusercontent.com/allowed-domains
ipset=/api.anthropic.com/api-staging.anthropic.com/files.anthropic.com/allowed-domains
ipset=/sentry.io/update.code.visualstudio.com/allowed-domains
ipset=/pypi.org/files.pythonhosted.org/allowed-domains
+1 -1
View File
@@ -69,7 +69,7 @@ fi
# Named volumes mounted into /workspace (build caches) start root-owned.
# Chown the mountpoint to match the workspace owner so the dev user can
# write into them. Non-recursive: contents are created by the dev user
# (e.g. via `npm ci`) and don't need re-chown on every start.
# (e.g. via `bun install`) and don't need re-chown on every start.
for vol in /workspace/web/node_modules /workspace/web/.next; do
[ -d "$vol" ] || continue
if ! chown "$WS_UID":"$WS_GID" "$vol" 2>&1; then
+2 -1
View File
@@ -55,7 +55,8 @@ ALLOWED_DOMAINS=(
"static.crates.io"
"archive.ubuntu.com"
"security.ubuntu.com"
"deb.nodesource.com"
"bun.sh"
"objects.githubusercontent.com"
)
for domain in "${ALLOWED_DOMAINS[@]}"; do
+5 -7
View File
@@ -27,20 +27,18 @@ jobs:
with:
persist-credentials: false
- name: Setup node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # ratchet:actions/setup-node@v4
- name: Setup bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # ratchet:oven-sh/setup-bun@v2 # zizmor: ignore[cache-poisoning] test-only workflow; no deploy artifacts
with:
node-version: 24
cache: "npm" # zizmor: ignore[cache-poisoning] test-only workflow; no deploy artifacts
cache-dependency-path: ./web/package-lock.json
bun-version: "1.3.13"
- name: Install node dependencies
working-directory: ./web
run: npm ci
run: bun install --frozen-lockfile
- name: Run Jest tests
working-directory: ./web
run: npm test -- --ci --coverage --maxWorkers=50%
run: bun run test -- --ci --coverage --maxWorkers=50%
- name: Upload coverage reports
if: always()
+16 -22
View File
@@ -317,30 +317,27 @@ jobs:
with:
persist-credentials: false
- name: Setup node
# zizmor: ignore[cache-poisoning] ephemeral runners; no release artifacts
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # ratchet:actions/setup-node@v4
- name: Setup bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # ratchet:oven-sh/setup-bun@v2 # zizmor: ignore[cache-poisoning] ephemeral runners; no release artifacts
with:
node-version: 24
cache: "npm" # zizmor: ignore[cache-poisoning]
cache-dependency-path: ./web/package-lock.json
bun-version: "1.3.13"
- name: Install node dependencies
working-directory: ./web
run: npm ci
run: bun install --frozen-lockfile
- name: Cache playwright cache
# zizmor: ignore[cache-poisoning] ephemeral runners; no release artifacts
uses: runs-on/cache@a5f51d6f3fece787d03b7b4e981c82538a0654ed
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-npm-${{ hashFiles('web/package-lock.json') }}
key: ${{ runner.os }}-playwright-bun-${{ hashFiles('web/bun.lock') }}
restore-keys: |
${{ runner.os }}-playwright-npm-
${{ runner.os }}-playwright-bun-
- name: Install playwright browsers
working-directory: ./web
run: npx playwright install --with-deps
run: bunx playwright install --with-deps
- name: Setup test license
uses: ./.github/actions/setup-test-license
@@ -393,7 +390,7 @@ jobs:
env:
PROJECT: ${{ matrix.project }}
run: |
npx playwright test --project ${PROJECT}
bunx playwright test --project ${PROJECT}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
if: always()
@@ -565,30 +562,27 @@ jobs:
with:
persist-credentials: false
- name: Setup node
# zizmor: ignore[cache-poisoning] ephemeral runners; no release artifacts
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # ratchet:actions/setup-node@v4
- name: Setup bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # ratchet:oven-sh/setup-bun@v2 # zizmor: ignore[cache-poisoning] ephemeral runners; no release artifacts
with:
node-version: 24
cache: "npm" # zizmor: ignore[cache-poisoning]
cache-dependency-path: ./web/package-lock.json
bun-version: "1.3.13"
- name: Install node dependencies
working-directory: ./web
run: npm ci
run: bun install --frozen-lockfile
- name: Cache playwright cache
# zizmor: ignore[cache-poisoning] ephemeral runners; no release artifacts
uses: runs-on/cache@a5f51d6f3fece787d03b7b4e981c82538a0654ed
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-npm-${{ hashFiles('web/package-lock.json') }}
key: ${{ runner.os }}-playwright-bun-${{ hashFiles('web/bun.lock') }}
restore-keys: |
${{ runner.os }}-playwright-npm-
${{ runner.os }}-playwright-bun-
- name: Install playwright browsers
working-directory: ./web
run: npx playwright install --with-deps
run: bunx playwright install --with-deps
- name: Setup test license
uses: ./.github/actions/setup-test-license
@@ -634,7 +628,7 @@ jobs:
- name: Run Playwright tests (lite)
working-directory: ./web
run: npx playwright test --project lite
run: bunx playwright test --project lite
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
if: always()
+5 -7
View File
@@ -29,15 +29,13 @@ jobs:
python-version: "3.11"
- name: Setup Terraform
uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # ratchet:hashicorp/setup-terraform@v4.0.0
- name: Setup node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # ratchet:actions/setup-node@v6
with: # zizmor: ignore[cache-poisoning]
node-version: 24
cache: "npm"
cache-dependency-path: ./web/package-lock.json
- name: Setup bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # ratchet:oven-sh/setup-bun@v2 # zizmor: ignore[cache-poisoning]
with:
bun-version: "1.3.13"
- name: Install node dependencies
working-directory: ./web
run: npm ci
run: bun install --frozen-lockfile
- uses: j178/prek-action@6ad80277337ad479fe43bd70701c3f7f8aa74db3
env:
SKIP: ty
+8 -10
View File
@@ -21,27 +21,25 @@ jobs:
with:
persist-credentials: false
- name: Setup node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # ratchet:actions/setup-node@v4
- name: Setup bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # ratchet:oven-sh/setup-bun@v2
with:
node-version: 24
cache: "npm"
cache-dependency-path: ./web/package-lock.json
bun-version: "1.3.13"
- name: Pull Vercel Environment Information
run: npx --yes ${{ env.VERCEL_CLI }} pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
run: bunx ${{ env.VERCEL_CLI }} pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Opal package
- name: Install dependencies and build Opal
working-directory: ./web
run: npm ci && npm run build --workspace=lib/opal
run: bun install --frozen-lockfile && bun run --filter './lib/opal' build
- name: Build Project Artifacts
run: npx --yes ${{ env.VERCEL_CLI }} build --token=${{ secrets.VERCEL_TOKEN }}
run: bunx ${{ env.VERCEL_CLI }} build --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy Project Artifacts to Vercel
id: deploy
run: |
DEPLOYMENT_URL=$(npx --yes ${{ env.VERCEL_CLI }} deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})
DEPLOYMENT_URL=$(bunx ${{ env.VERCEL_CLI }} deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})
echo "url=$DEPLOYMENT_URL" >> "$GITHUB_OUTPUT"
- name: Update PR comment with deployment URL
+10 -5
View File
@@ -6,10 +6,10 @@ on:
- "opal/v*.*.*"
jobs:
npm:
publish:
runs-on: ubuntu-latest
# Pin Node by image digest. The container ships with Node baked in, so the workflow
# never invokes `actions/setup-node` and the runner toolcache is never restored —
# Pin Node by image digest. The container ships with Node baked in, so npm publish
# and its OIDC trusted-publishing flow work without any toolcache restore —
# mitigates zizmor's cache-poisoning class of finding at the source rather than
# suppressing it. Bumping Node = bump the digest.
container:
@@ -28,6 +28,11 @@ jobs:
with:
persist-credentials: false
- name: Setup bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # ratchet:oven-sh/setup-bun@v2 # zizmor: ignore[cache-poisoning]
with:
bun-version: "1.3.13"
- name: Configure npm registry
run: |
printf 'registry=https://registry.npmjs.org/\n' > "$HOME/.npmrc"
@@ -42,11 +47,11 @@ jobs:
fi
- name: Install workspace deps
run: npm ci
run: bun install --frozen-lockfile
working-directory: web
- name: Build opal
run: npm run build
run: bun run build
- name: Publish to npm
run: npm publish --provenance --access public
+7 -9
View File
@@ -19,7 +19,7 @@ on:
- "web/src/refresh-components/**"
- "web/.storybook/**"
- "web/package.json"
- "web/package-lock.json"
- "web/bun.lock"
permissions:
contents: read
jobs:
@@ -32,24 +32,22 @@ jobs:
with:
persist-credentials: false
- name: Setup node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # ratchet:actions/setup-node@v4
- name: Setup bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # ratchet:oven-sh/setup-bun@v2
with:
node-version: 24
cache: "npm"
cache-dependency-path: ./web/package-lock.json
bun-version: "1.3.13"
- name: Install dependencies
working-directory: web
run: npm ci
run: bun install --frozen-lockfile
- name: Build Storybook
working-directory: web
run: npm run storybook:build
run: bun run storybook:build
- name: Deploy to Vercel (Production)
working-directory: web
run: npx --yes "$VERCEL_CLI" deploy storybook-static/ --prod --yes --token="$VERCEL_TOKEN"
run: bunx "$VERCEL_CLI" deploy storybook-static/ --prod --yes --token="$VERCEL_TOKEN"
notify-slack-on-failure:
needs: Deploy-Storybook
+14 -14
View File
@@ -129,42 +129,42 @@ repos:
- repo: local
hooks:
- id: npm-install
name: npm install
description: "Automatically run 'npm install' after a checkout, pull or rebase"
- id: bun-install
name: bun install
description: "Automatically run 'bun install' after a checkout, pull or rebase"
language: system
entry: bash -c 'cd web && npm install --no-save'
entry: bash -c 'cd web && bun install'
pass_filenames: false
files: ^web/(package(-lock)?\.json|lib/opal/package\.json)$
files: ^web/(package\.json|bun\.lock|lib/opal/package\.json)$
stages: [post-checkout, post-merge, post-rewrite]
- id: npm-install-check
name: npm install --package-lock-only
description: "Check the 'web/package-lock.json' is updated"
- id: bun-install-check
name: bun install
description: "Check the 'web/bun.lock' is updated"
language: system
entry: bash -c 'cd web && npm install --package-lock-only'
entry: bash -c 'cd web && bun install'
pass_filenames: false
files: ^web/(package(-lock)?\.json|lib/opal/package\.json)$
files: ^web/(package\.json|bun\.lock|lib/opal/package\.json)$
- id: oxfmt
name: oxfmt
entry: npx --prefix web oxfmt
entry: bash -c 'cd web && bunx oxfmt "$@"' _
language: system
types_or: [html, css, javascript, ts, tsx]
- id: oxlint
name: oxlint
entry: bash -c 'cd web && npx oxlint'
entry: bash -c 'cd web && bunx oxlint'
language: system
pass_filenames: false
types_or: [javascript, ts, tsx]
# Uses tsgo (TypeScript's native Go compiler) for ~10x faster type checking.
# This is a preview package - if it breaks:
# 1. Try updating: cd web && npm update @typescript/native-preview
# 1. Try updating: cd web && bun update @typescript/native-preview
# 2. Or fallback to tsc: replace 'tsgo' with 'tsc' below
- id: typescript-check
name: TypeScript type check
entry: bash -c 'cd web && npx tsgo --noEmit --project tsconfig.types.json'
entry: bash -c 'cd web && bunx tsgo --noEmit --project tsconfig.types.json'
language: system
pass_filenames: false
files: ^web/.*\.(ts|tsx)$
+8 -13
View File
@@ -93,7 +93,7 @@ Onyx being a fully functional app, relies on some external software, specificall
- **Python 3.11** — If using a lower version, modifications will have to be made to the code. Higher versions may have library compatibility issues.
- **Docker** — Required for running external services (Postgres, OpenSearch, Redis, MinIO).
- **Node.js v22** — We recommend using [nvm](https://github.com/nvm-sh/nvm) to manage Node installations.
- **Bun** — We use [bun](https://bun.sh) as the JavaScript package manager. Install it from https://bun.sh/docs/installation.
### Backend: Python Requirements
@@ -130,15 +130,10 @@ uv run playwright install
### Frontend: Node Dependencies
```bash
nvm install 22 && nvm use 22
node -v # verify your active version
```
Navigate to `onyx/web` and run:
```bash
npm i
bun install
```
### Formatting and Linting
@@ -159,19 +154,19 @@ uv run ty check
#### Frontend
We use `oxfmt` for formatting. The desired version will be installed via `npm i` from the `onyx/web` directory. To run the formatter:
We use `oxfmt` for formatting. The desired version will be installed via `bun install` from the `onyx/web` directory. To run the formatter:
```bash
npx oxfmt . # from onyx/web
bunx oxfmt . # from onyx/web
```
Pre-commit will also run oxfmt automatically on files you've recently touched. If re-formatted, your commit will fail. Re-stage your changes and commit again.
We use `oxlint` for linting. The desired version will be installed via `npm i` from the `onyx/web` directory. To run the linter:
We use `oxlint` for linting. The desired version will be installed via `bun install` from the `onyx/web` directory. To run the linter:
```bash
npx oxlint # from onyx/web
npx oxlint --fix # auto-fix what it can
bunx oxlint # from onyx/web
bunx oxlint --fix # auto-fix what it can
```
Pre-commit will also run oxlint automatically. If it reports errors, fix them and commit again.
@@ -230,7 +225,7 @@ docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d index relat
To start the frontend, navigate to `onyx/web` and run:
```bash
npm run dev
bun run dev
```
Next, start the model server which runs the local NLP models. Navigate to `onyx/backend` and run:
+3 -3
View File
@@ -10,8 +10,8 @@ The Onyx Storybook covers the full component library — from low-level `@opal/c
```bash
cd web
npm run storybook # dev server on http://localhost:6006
npm run storybook:build # static build to storybook-static/
bun run storybook # dev server on http://localhost:6006
bun run storybook:build # static build to storybook-static/
```
The dev server hot-reloads when you edit a component or story file.
@@ -64,7 +64,7 @@ Use the theme toggle (paint roller icon) in the Storybook toolbar to switch betw
## Deployment
The production Storybook is deployed as a static site on Vercel. The build runs `npm run storybook:build` which outputs to `storybook-static/`, and Vercel serves that directory.
The production Storybook is deployed as a static site on Vercel. The build runs `bun run storybook:build` which outputs to `storybook-static/`, and Vercel serves that directory.
Deploys are triggered on merges to `main` when files in `web/lib/opal/`, `web/src/refresh-components/`, or `web/.storybook/` change.
+5 -3
View File
@@ -11,18 +11,20 @@ founders@onyx.app for more information. Please visit https://github.com/onyx-dot
FROM base AS builder
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
COPY --from=oven/bun:1-alpine@sha256:5acc90a93e91ff07bf72aa90a7c9f0fa189765aec90b47bdbf2152d2196383c0 /usr/local/bin/bun /usr/local/bin/bun
COPY --from=oven/bun:1-alpine@sha256:5acc90a93e91ff07bf72aa90a7c9f0fa189765aec90b47bdbf2152d2196383c0 /usr/local/bin/bunx /usr/local/bin/bunx
WORKDIR /app
# Copy package files + the full opal workspace source so that opal's `prepare`
# lifecycle hook (which runs during `npm ci` for workspace packages) can build
# lifecycle hook (which runs during `bun install` for workspace packages) can build
# `dist/` artifacts before Next.js resolves package exports. opal's tsconfig
# extends web's `tsconfig.json`, so that file must also be present at install
# time for the DTS build to succeed.
COPY package.json package-lock.json tsconfig.json ./
COPY package.json bun.lock tsconfig.json ./
COPY lib/opal/ ./lib/opal/
# Install dependencies. opal's `prepare` script builds dist/ as part of install.
RUN npm ci
RUN bun install --frozen-lockfile
# pull in remaining source code
COPY . .
+8 -8
View File
@@ -4,13 +4,13 @@ This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next
## Getting Started
Install node / npm: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm
Install all dependencies: `npm i`.
Install bun: https://bun.sh/docs/installation
Install all dependencies: `bun install`.
Then, run the development server:
```bash
npm run dev
bun run dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
@@ -62,27 +62,27 @@ Bring up the entire application.
0. Install playwright dependencies
```bash
npx playwright install
bunx playwright install
```
1. Run playwright
```bash
npx playwright test
bunx playwright test
```
To run a single test:
```bash
npx playwright test landing-page.spec.ts
bunx playwright test landing-page.spec.ts
```
If running locally, interactive options can help you see exactly what is happening in
the test.
```bash
npx playwright test --ui
npx playwright test --headed
bunx playwright test --ui
bunx playwright test --headed
```
2. Inspect results
+2931
View File
File diff suppressed because it is too large. Load diff
+4 -4
View File
@@ -115,19 +115,19 @@ web/lib/opal/
Opal reuses `/web/node_modules` — it does not have its own `node_modules`. To add a runtime
dependency, declare it under `peerDependencies` in `web/lib/opal/package.json` AND add the
matching version in the root `web/package.json` `dependencies` block, then run `npm i` in `/web`
matching version in the root `web/package.json` `dependencies` block, then run `bun install` in `/web`
so Onyx's web app keeps building.
The package is consumed by `web/` as a workspace via `web/package.json`'s `"@onyx-ai/opal":
"./lib/opal"`. During Onyx development, `web/` resolves Opal source through the `@opal/*`
TypeScript path alias (defined in `web/tsconfig.json`), so changes are picked up live without
running `npm run build`.
running `bun run build`.
To produce the published artifact:
```sh
cd web/lib/opal
npm run build # tsup -> dist/, then bundle-css.mjs -> dist/styles.css
bun run build # tsup -> dist/, then bundle-css.mjs -> dist/styles.css
```
## Releasing to npm
@@ -151,7 +151,7 @@ Steps:
```
4. The workflow runs automatically on tag push. It builds (`tsup` + CSS barrel) and runs
`npm publish --provenance --access public`. Watch the run under the Actions tab; verify
`bun publish --provenance --access public`. Watch the run under the Actions tab; verify
the new version on https://www.npmjs.com/package/@onyx-ai/opal.
The tag pattern must match `opal/v*.*.*` for the workflow to fire.
+1 -1
View File
@@ -64,7 +64,7 @@
},
"scripts": {
"build": "tsup && node scripts/bundle-css.mjs",
"prepare": "npm run build"
"prepare": "bun run build"
},
"dependencies": {
"clsx": "^2.0.0",
-18365
View File
File diff suppressed because it is too large. Load diff