Repository navigation
fix(cli): serve gains --no-open, no bare stack after headless browser-open failure - #5302
Merged
Merged
Conversation
…-open failure `serve` hardcoded Vite's `open: true` with no way to turn it off, unlike `dev` (which already ships `--no-open`) — mirror that flag exactly, default unchanged. Separately, a failed browser-open in a headless environment surfaced Vite's bare `Error: spawn xdg-open ENOENT` Node stack after the success banner (Vite logs it via `logger.error(err.stack)` with no context); supply a `customLogger` that replaces exactly that message with a short contextual line and passes every other log call through unchanged. Fixes #4924 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4924
Re-derived on current
origin/main(7260a1ed4, ahead of the5ffcc1432the card wasmeasured on) before editing:
openwas still hardcodedtrueincommands/serve.tsandservestill had no--no-open, so both halves of the card were still live.Half 1 —
--no-openservehardcoded Vite'sopen: true; its commander options were only--port/--host.devalready ships--no-open(declared incli.ts, threaded asoptions.open !== falsein
dev.ts).servenow mirrors that exactly — same flag name, same threading expression,same default. The default is unchanged: with the flag omitted,
servestill opens abrowser exactly as it always has.
Half 2 — the headless spawn failure
Read Vite 8.2.1's own
startBrowserProcess(src/node/server/openBrowser.ts): it alreadycatches a failed
open(url), but reports it vialogger.error(err.stack || err.message)with no
{ timestamp: true }— so the default logger prints the bare NodeChildProcessstack with no
[vite]prefix and no context, and because that promise chain isfire-and-forget from
server.listen(), it lands after the success banner. There isnothing in
serve.tsto try/catch — the error never leaves Vite.I chose a short contextual line over silence:
servenow supplies acustomLoggerthat wraps Vite's default logger and replaces exactly that message with
Every other log call — including unrelated errors — passes through unchanged. A live
repro (
createServer({ server: { open: true } })withBROWSERpointed at a nonexistentbinary) reproduced the exact reported shape before the fix:
and the contextual line after it.
A necessary file-surface extension
The claimed surface was
packages/cli/src/commands/serve.ts+ its tests, butdev's own--no-openis declared incli.ts(commander's.option()chain), not indev.ts—mirroring
dev's pattern forservestructurally requires the matching one-line additionin
cli.ts. No other in-flight claim touchespackages/cli, so there is no collision;flagging this per the file-surface note rather than silently expanding scope.
Serial constraint
Sibling card #4923 (project-root detection, same command) is untouched — separate defect,
separate PR, per triage. #4923 remains open and is not addressed here.
Testing
packages/cli/src/__tests__/serve.test.ts(new).unit-project*.test.tsfiles acrossthis whole monorepo share one module graph (
isolate: false), sovi.mock('vite')wouldleak into every other package's tests sharing the worker — the same constraint
project-source.test.tsdocuments. Both fixes are therefore pinned on the two pure,exported seams
serve.tswas refactored to expose —resolveServeOpenOption(the configvalue the flag threads into) and
createServeLogger(the spawn-failure interception) —neither of which touches Vite's runtime, so nothing needs mocking:
resolveServeOpenOption: default (undefined) →true; explicittrue→true;--no-open(false) →false.createServeLogger: the realError: spawn xdg-open ENOENTstack shape (confirmed viathe live repro above, not invented) is replaced with the contextual line and never
reaches the base logger; an unrelated real error passes straight through unmodified
(counter-probe: the interception is selective, not a blanket swallow); a non-Vite
spawn-ENOENT message that isn't the
Error: spawn ... ENOENTshape also passes throughunmodified (counter-probe: the pattern is anchored, not a bare
"ENOENT"substringmatch);
info/warn/warnOnce/clearScreen/hasErrorLoggeddelegate unchanged; andhasWarnedmirrors the base logger live rather than freezing at construction time.Commands run (repo root, canonical invocation), at head
219a6792f:Reverse verification: committed the fix, predicted that reverting
serve.ts/cli.ts(keeping the new test file) would fail all 9 new tests because they import
createServeLogger/resolveServeOpenOption, which wouldn't exist — then reverted and ran.Observed: exactly those 9 tests failed (each
TypeError: ... is not a functionat thecall site — Vitest's ESM transform resolves a missing named export to
undefinedatruntime rather than a hard link-time
SyntaxError, a refinement on the predicted mechanismbut not the predicted outcome), the other 8 files / 179 tests stayed green. Restored the
fix; re-ran — 188/188 green again at the same head.
scripts/pm/dispatch-gates.mjsdoesnot exist in this repo (objectstack-only tooling); ran the applicable
check:*gatesindividually instead, listed above.
Generated by Claude Code