Skip to content

docs: run the production frontend with bun scripts/serve.ts - #272

Merged
edbfi merged 1 commit into
mainfrom
docs/direct-start-command
Oct 7, 2026
Merged

edbfi merged 1 commit into
mainfrom
docs/direct-start-command

Conversation

@edbfi

@edbfi edbfi commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Summary

The README files, both CLAUDE.md files and .env.example tell people to start the production frontend with bun run start. With Bun 1.4.2's default system shell, bun run start and bun start deliver one terminal Ctrl+C to the server twice: the terminal signals the foreground process group, and bun run also forwards the signal to its child, as npm does. adapter-bun 1.0.0 treats the second delivery as a second signal (if (shutting_down) return process.exit(1);), and the front's own handler does the same before the adapter has loaded, so a single Ctrl+C exits 1 at once with no SHUTDOWN_TIMEOUT drain. A group SIGTERM is doubled the same way. NODE_ENV=production bun scripts/serve.ts, run from frontend/ (what the start script runs), receives each signal once.

This PR changes the documented production command to NODE_ENV=production bun scripts/serve.ts, says why, and names the working directory. It is docs only: the start package script, the code, the Docker image and CI are unchanged. Same defect and fix shape as edbfi/poyo-studio#90.

Changes

  • README.md, "Development and production frontend": the block now says it runs in frontend/ and starts with NODE_ENV=production bun scripts/serve.ts, followed by one line saying it is what the start script runs and why bun run start and bun start are not used. "With ORIGIN set, start fronts the SvelteKit server" now names scripts/serve.ts. The note that the container runs the same entry point stays true (the s6 run file in zondarr-docker execs bun ./scripts/serve.ts).
  • frontend/README.md: the "Start the built server" row is NODE_ENV=production bun scripts/serve.ts (from frontend/, since the --cwd prefix in the table's intro applies only to bun run scripts), with one paragraph below the table on why.
  • CLAUDE.md: the production note names the direct command, its directory, and why not bun run start.
  • frontend/CLAUDE.md: the production note names the direct command and why (one Ctrl+C or group SIGTERM arrives twice under bun run start; the second exits 1 without the drain).
  • .env.example: the ORIGIN comment names the frontend server by its direct command instead of bun run start.

No existing doc in this repository said "a second Ctrl+C / SIGTERM stops at once" or described repeated SIGHUPs, so there was no such wording to re-check. The code comment in frontend/scripts/serve.ts about the hangup arriving twice under bun run start is accurate and left alone (docs-only PR).

Rationale

Changing how bun run launches the script (a bunfig [run] shell = "bun" or --shell=bun) was considered and not chosen: under the Bun shell, SIGTERM/SIGHUP sent to the launcher PID kill the launcher and orphan the server (oven-sh/bun#41802, still open). The system-shell double forwarding is intentional npm parity in Bun (oven-sh/bun#36711). Running the front directly avoids both.

Validation

Signal run on this repository's built frontend, Bun 1.4.2 on macOS, 2026-10-07, origin/main 8a51968: bun run build, then build/, package.json and scripts/serve.ts copied into a fresh temp directory (with node_modules linked) and started through each launcher in its own process group on a free loopback port, with SHUTDOWN_TIMEOUT=3 and INTERNAL_API_URL pointing at a stand-in backend that accepts requests and never answers. One group signal was then sent, as a terminal does.

Launch Case One group SIGINT (Ctrl+C) One group SIGTERM
bun run start ORIGIN set (front), idle exit 1 after 0.00 s exit 1 after 0.01 s
NODE_ENV=production bun scripts/serve.ts ORIGIN set (front), idle exit 0 after 0.01 s exit 0 after 0.01 s
bun run start ORIGIN set, one /api request open exit 1 after 0.01 s; the request got an empty reply (connection dropped) exit 1 after 0.01 s; empty reply
NODE_ENV=production bun scripts/serve.ts ORIGIN set, one /api request open exit 0 after 3.04 s (the SHUTDOWN_TIMEOUT deadline); the request got a 503 at the deadline exit 0 after 3.05 s; 503
bun run start ORIGIN unset (adapter only), idle exit 1 after 0.01 s exit 1 after 0.01 s
NODE_ENV=production bun scripts/serve.ts ORIGIN unset (adapter only), idle exit 0 after 0.01 s exit 0 after 0.00 s

Under bun run start the adapter printed "Waiting for 1 requests to finish before shutting down... Press Ctrl+C again to force shutdown." and exited 1 in the same instant: the forwarded copy of the one Ctrl+C was taken as that second press. Under the direct command it waited out the drain and exited 0.

Local gates on head 83f5dc0 (the repository's only workflow is Pullfrog):

  • prek run --from-ref origin/main --to-ref HEAD: every applicable hook passed (whitespace, end of file, line endings, merge conflicts, case conflicts, large files, private keys, branch guard, gitleaks); Biome, Ruff and the JSON/TOML/YAML checks were skipped because no matching file changed.
  • prek run --hook-stage commit-msg: Conventional Commit passed.
  • bun run check:biome (biome ci .., from frontend/): passed, 267 files, no errors; its 17 warnings and 3 infos are in source files this PR does not touch.
  • pre-push hooks on publish: TypeScript Check (bun run --cwd frontend check) and Frontend Tests (bun run --cwd frontend test) passed.
  • git diff origin/main --stat: .env.example, CLAUDE.md, README.md, frontend/CLAUDE.md, frontend/README.md only.

With Bun 1.4.2's default system shell, `bun run start` and `bun start`
deliver one terminal Ctrl+C to the server twice (the terminal signals the
foreground group and `bun run` forwards it as npm does), so adapter-bun
treats it as a second signal and exits 1 at once without the
SHUTDOWN_TIMEOUT drain. A group SIGTERM is doubled the same way.
`NODE_ENV=production bun scripts/serve.ts`, run from frontend/, receives
each signal once.

Point README.md, frontend/README.md, CLAUDE.md, frontend/CLAUDE.md and
.env.example at the direct command, say why, and name the working
directory. The `start` package script is unchanged.

Signed-off-by: edbfi <326875205+edbfi@users.noreply.github.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

Reviewed the full docs-only diff (5 files) against main, and checked the documented command against frontend/package.json and the remaining references in the repo.

  • README.md and frontend/README.md — the production start command is now NODE_ENV=production bun scripts/serve.ts from frontend/, with a short explanation of why bun run start and bun start are avoided.
  • CLAUDE.md and frontend/CLAUDE.md — the production notes name the direct command, its working directory and the double-signal reason.
  • .env.example — the ORIGIN comment names the direct command instead of bun run start.

The new command matches the start script in frontend/package.json exactly. No stale bun run start recommendations remain; the two leftover mentions in frontend/scripts/serve.ts and serve.test.ts are accurate code comments about the double hangup.

ℹ️ Nitpicks

  • The command string now lives in package.json and in five doc locations. If the start script changes (for example a new flag), the docs will drift silently. Not worth fixing here.

Pullfrog  | View workflow run | Using claude-sonnet-5-5 | 𝕏

@edbfi

edbfi commented Oct 7, 2026

Copy link
Copy Markdown
Owner Author

Re the nitpick in this review (the command string now lives in package.json and five doc locations, so a change to the start script could drift silently): REJECTED for this PR. Naming the direct command in the docs is the owner's decision for this change, and each place says it is the command the start script runs, so a later change to the script points at them. A drift check would be new tooling, outside this docs-only scope.

@edbfi
edbfi merged commit 9321305 into main Oct 7, 2026
1 check passed
@edbfi
edbfi deleted the docs/direct-start-command branch October 7, 2026 09:41
edbfi added a commit that referenced this pull request Oct 7, 2026
…273)

The SIGHUP comment in frontend/scripts/serve.ts explains the double hangup under `bun run start`. Keep that and add that the production command, `NODE_ENV=production bun scripts/serve.ts` from frontend/, gets it once, as CLAUDE.md says since #272. Comment only.

Signed-off-by: edbfi <326875205+edbfi@users.noreply.github.com>
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.

1 participant