Run on Bun: bun install, bun --bun next, both dev2 sites on Bun (#222)
Some checks are pending
CI / build (push) Waiting to run
Deploy to dev2 / deploy (push) Waiting to run
test / test (push) Waiting to run

* Run on Bun: bun install, bun --bun next, both dev2 sites on Bun

Moves logicsrc.com and app.logicsrc.com (one image) off Node + npm onto Bun,
following the fleet recipe (phonenumbers.bot pilot).

- Package manager: bun.lock migrated from package-lock.json, so every resolved
  version is unchanged; packageManager bun@1.4.2. Root scripts run each
  workspace with `bun run --cwd <dir>` instead of `npm --workspace`.
- Bun 1.4.2, not the fleet's 1.4.0: 1.4.0 re-resolves this workspace's `file:`
  cross-references differently on every install, so its own lockfile never
  passes --frozen-lockfile. 1.4.2 is stable on it.
- Runtime: logicsrc-web runs `bun --bun next build/start`; apps/pwa (Express,
  app.logicsrc.com) runs `bun src/server.mjs`.
- Image: .nixpacks/Dockerfile (the path both dev2 compose stacks build) is now
  a hand-written oven/bun image carrying the whole workspace, run as the
  non-root bun user. ENTRYPOINT stays `bash -l -c` so a compose `command:` is
  one string, as before; app.logicsrc.com's compose starts it with
  "npm --workspace @logicsrc/pwa run start", which .nixpacks/npm (the image's
  only `npm`) turns into `bun run start` in apps/pwa. Port 3000, the PUBLIC_URL
  build arg and the / health path are unchanged. The nixpacks .nix and
  build.sh are gone.
- CI: both workflows install with bun and run every script through bun (Node
  stays only as the interpreter for vitest/tsc/node --test/Playwright, as
  before), and CI now boots the site under Bun.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* ci: boot check on port 3100 and stop it before Playwright needs 3000

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(web): keep next dev on port 5174, which Playwright waits on

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Anthony Ettinger 2026-10-01 08:14:40 -07:00 • committed by GitHub
parent e62c546a1e
commit 20797a98f1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 1917 additions and 9609 deletions

View file

@ -1,36 +1,48 @@
FROM ghcr.io/railwayapp/nixpacks:ubuntu-1745885067
# syntax=docker/dockerfile:1
#
# logicsrc.com and app.logicsrc.com, run on Bun. One image serves both sites.
#
# This file lives at .nixpacks/Dockerfile because that is the path dev2's compose
# stacks build (cli-tools dev2/dev2-site provision records it per site, and
# re-provisioning keeps it). It used to be nixpacks output (Node + npm); it is now
# a hand-written Bun image, so do not regenerate it with nixpacks.
#
# Contract with dev2, unchanged from the Node image:
# - Listens on 3000 inside the container and answers / for the deploy health check.
# - ENTRYPOINT is `bash -l -c`, so a compose `command:` is ONE string, as before.
# logicsrc.com uses the default CMD; app.logicsrc.com's compose overrides it
# with "npm --workspace @logicsrc/pwa run start", which .nixpacks/npm (the
# image's `npm`) turns into `bun run start` in apps/pwa.
# - Takes the PUBLIC_URL build arg; secrets come from app.env at run time.
#
# The whole workspace tree ships, not a Next standalone bundle: app.logicsrc.com
# runs apps/pwa (Express) from the same image, with its own dependencies.
#
# Bun 1.4.2, not the fleet's usual 1.4.0: 1.4.0 re-resolves this workspace's
# `file:` cross-references differently on every install, so its own lockfile
# never passes --frozen-lockfile. 1.4.2 is stable on it.
ENTRYPOINT ["/bin/bash", "-l", "-c"]
WORKDIR /app/
FROM oven/bun:1.4.2-slim AS build
WORKDIR /app
ARG PUBLIC_URL
ENV PUBLIC_URL=$PUBLIC_URL
COPY .nixpacks/nixpkgs-ffeebf0acf3ae8b29f8c7049cd911b9636efd7e7.nix .nixpacks/nixpkgs-ffeebf0acf3ae8b29f8c7049cd911b9636efd7e7.nix
RUN nix-env -if .nixpacks/nixpkgs-ffeebf0acf3ae8b29f8c7049cd911b9636efd7e7.nix && nix-collect-garbage -d
ARG CI NIXPACKS_METADATA NIXPACKS_NODE_VERSION NODE_ENV NPM_CONFIG_PRODUCTION
ENV CI=$CI NIXPACKS_METADATA=$NIXPACKS_METADATA NIXPACKS_NODE_VERSION=$NIXPACKS_NODE_VERSION NODE_ENV=$NODE_ENV NPM_CONFIG_PRODUCTION=$NPM_CONFIG_PRODUCTION
# setup phase
# noop
# install phase
ENV NIXPACKS_PATH=/app/node_modules/.bin:$NIXPACKS_PATH
COPY . /app/.
RUN --mount=type=cache,id=myZsC0wNW9Q-/root/npm,target=/root/.npm npm ci
# build phase
COPY . /app/.
RUN --mount=type=cache,id=myZsC0wNW9Q-apps/logicsrc-web/next/cache,target=/app/apps/logicsrc-web/.next/cache --mount=type=cache,id=myZsC0wNW9Q-node_modules/cache,target=/app/node_modules/.cache npm run build
RUN printf '\nPATH=/app/node_modules/.bin:$PATH' >> /root/.profile
# start
COPY . /app
CMD ["npm run start"]
ENV PUBLIC_URL=$PUBLIC_URL \
NEXT_TELEMETRY_DISABLED=1
COPY . .
RUN bun install --frozen-lockfile
# Every workspace build (tsc, vite, `bun --bun next build`), in dependency order.
RUN bun run build
FROM oven/bun:1.4.2-slim AS runtime
WORKDIR /app
ENV NODE_ENV=production \
NEXT_TELEMETRY_DISABLED=1 \
PORT=3000
COPY --from=build --chown=bun:bun /app /app
COPY --chown=root:root .nixpacks/npm /usr/local/bin/npm
# The oven/bun image ships a non-root `bun` user.
USER bun
EXPOSE 3000
ENTRYPOINT ["/bin/bash", "-l", "-c"]
# logicsrc.com: Next's own entry file run directly by Bun, one process, no
# wrapper (`bun run start` would leave three bun processes stacked up).
CMD ["cd apps/logicsrc-web && exec bun --bun /app/node_modules/next/dist/bin/next start"]

View file

@ -1 +0,0 @@
docker build /home/anthony/src/profullstack/logicsrc/.claude/worktrees/dev2-logicsrc.com-8sr7z6_r -f /home/anthony/src/profullstack/logicsrc/.claude/worktrees/dev2-logicsrc.com-8sr7z6_r/.nixpacks/Dockerfile -t 4c321096-0f24-4fcc-8a9b-8098036fecc1 --build-arg CI=true --build-arg NIXPACKS_METADATA=node --build-arg NIXPACKS_NODE_VERSION=22 --build-arg NODE_ENV=production --build-arg NPM_CONFIG_PRODUCTION=false

View file

@ -1,21 +0,0 @@
{ }:
let pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/ffeebf0acf3ae8b29f8c7049cd911b9636efd7e7.tar.gz") { overlays = [ (import (builtins.fetchTarball "https://github.com/railwayapp/nix-npm-overlay/archive/main.tar.gz")) ]; };
in with pkgs;
let
APPEND_LIBRARY_PATH = "${lib.makeLibraryPath [ gcc-unwrapped ] }";
myLibraries = writeText "libraries" ''
export LD_LIBRARY_PATH="${APPEND_LIBRARY_PATH}:$LD_LIBRARY_PATH"
'';
in
buildEnv {
name = "ffeebf0acf3ae8b29f8c7049cd911b9636efd7e7-env";
paths = [
(runCommand "ffeebf0acf3ae8b29f8c7049cd911b9636efd7e7-env" { } ''
mkdir -p $out/etc/profile.d
cp ${myLibraries} $out/etc/profile.d/ffeebf0acf3ae8b29f8c7049cd911b9636efd7e7-env.sh
'')
nodejs_22 npm-9_x
];
}

28
.nixpacks/npm Executable file
View file

@ -0,0 +1,28 @@
#!/bin/sh
# npm compatibility shim for the Bun image (see .nixpacks/Dockerfile).
#
# dev2's compose for app.logicsrc.com starts this image with the fixed command
# string "npm --workspace @logicsrc/pwa run start" (rendered by cli-tools
# dev2-site from the old Railway start command). The image has no Node and no
# npm, so this translates exactly that shape, `npm [--workspace NAME] run
# SCRIPT [ARGS...]`, into `bun run SCRIPT` inside the workspace's directory.
# Anything else is refused loudly rather than guessed at.
set -eu
ROOT=/app
ws=""
if [ "${1:-}" = "--workspace" ] || [ "${1:-}" = "-w" ]; then ws=$2; shift 2; fi
if [ "${1:-}" != "run" ] || [ $# -lt 2 ]; then
echo "npm shim: only 'npm [--workspace NAME] run SCRIPT' is supported (got: $*)" >&2
exit 64
fi
shift
dir=$ROOT
if [ -n "$ws" ]; then
dir=""
for pj in "$ROOT"/apps/*/package.json "$ROOT"/packages/*/package.json "$ROOT"/plugins/*/package.json; do
if grep -q "\"name\": *\"$ws\"" "$pj"; then dir=$(dirname "$pj"); break; fi
done
[ -n "$dir" ] || { echo "npm shim: no workspace named $ws" >&2; exit 66; }
fi
cd "$dir"
exec bun run "$@"