mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
codex/cacheability-platform-io
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9b24683503 | fix(build): don't crash on benign floating asset-import errors (#1510) (#1846) | ||
|
|
fc5f7a6492 |
fix(dev): hoist socket-error backstop to module top-level so lifecycle events can't remove it (#916)
* debug(dev): hoist socket-error backstop to module top-level + opt-in trace Two changes intended to pin down why the process-level handler from PR #913 still doesn't catch the ECONNRESET trace some users report: 1. Move installation from inside configureServer to module top-level, guarded by Symbol.for to prevent double-install. Earlier versions tied teardown to httpServer 'close', which Vite emits on dep re-optimization, full reloads, and other lifecycle events — leaving a window where the listener is absent when a stale stream errors. Module-level install + Symbol guard removes that window entirely. 2. Add an opt-in console.warn marker behind VINEXT_DEBUG_SOCKET_ERRORS=1 that fires whenever the listener absorbs a peer-disconnect error. The visible `node:events:487 throw er; // Unhandled 'error' event` output otherwise leaves it ambiguous whether the listener never ran (install / lifecycle issue) or ran but was somehow bypassed (different async surface / dispatcher). The marker disambiguates. No behavior change for users not setting the env flag beyond the hoisting. Filter codes and re-throw shape are unchanged from #913. Refs #905. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: address bonk review on dev socket-error backstop Three issues from PR #916 review: 1. Module-top-level install was wrong — it ran during 'vinext build', 'vp pack', and Vitest worker imports too, so the JSDoc 'dev-only' claim was inaccurate and a real ECONNRESET from a pre-render fetch in CI would have been silently swallowed. Move the install back into configureServer (which only fires in dev) but **without** binding teardown to httpServer 'close' — that was the original lifecycle bug PR #913 had. Symbol.for guard makes re-invocation a no-op so the listener still survives server restarts within a session. 2. Restore the middleware-mode skip dropped in the previous commit. Embedders running vinext in middleware mode (Express/Connect) keep ownership of their own process-level handlers. Gated on server.httpServer, matching the prior PR #913 behavior. 3. Document the listener-ordering implication of installing during configureServer (registers late in the queue, so Sentry / structured logging / test-runner hooks still observe non-peer-disconnect errors before vinext's sync re-throw aborts iteration), and the Symbol.for first-loaded-wins caveat for the multi-version case. Refactor: collapse the duplicated `(err as Error & { code }).code` casts into a single `peerDisconnectCode` helper that returns the matched code or undefined, so the debug log path reuses it without recasting. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(dev): re-hoist socket-error backstop to module load (configureServer too late) The previous attempt to address bonk's review by moving install back into configureServer was wrong — it didn't restore working behavior: $ VINEXT_DEBUG_SOCKET_ERRORS=1 vp dlx vinext@455a61b dev ... GET /stage/oliver 200 in 1.1s node:events:487 throw er; // Unhandled 'error' event Error: read ECONNRESET ... No `[vinext] dev socket-error backstop installed` startup line. The function never ran. Cause: in vite-plus's plugin lifecycle, `server.httpServer` is null at the moment configureServer fires, so the `if (server.httpServer)` middleware-mode guard skipped install. Requests still get served (httpServer is created later) but the listener was never attached. Hoist back to module load. To address bonk's "loaded in build/test contexts too" concern, gate install on: - `process.env.VITEST === "true"` → Vitest worker imports - `process.argv` contains "build" → `vinext build` / `vp build` `process.argv` is read because the CLI entry imports index.ts before it has a chance to set an env var, and `configResolved` runs too late for module-load gating. Updated JSDoc to be honest about the install context, the listener- ordering implication, the middleware-mode embedder situation, and the Symbol.for first-loaded-wins caveat. Refs #905. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(dev): positive-gate socket backstop on argv[2]==='dev' Replace the negative VITEST/build skip list with a single positive check: install only when argv[2] === "dev". Matches `vinext dev`, `vp dev`, `vite dev`, and any CLI following the "<bin> dev" convention. Everything else — build, Vitest workers, library embedders with a custom runner — skips install, so genuine peer-disconnect errors surface normally in those contexts. Cleaner default: no listener unless we're confident this is a dev server invocation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(dev): gate socket backstop on Vite's command==='serve' Replace argv-sniffing with the canonical signal: Vite's `config()` hook receives `{ command: "serve" | "build" }` directly. Install the backstop only when `command === "serve"`. Works identically for `vinext dev`, `vp dev`, `vite dev`, and library embedders that call `createServer` themselves — anywhere Vite considers itself a dev server. `config()` runs before `configureServer` (so before httpServer matters) and before the dep-optimization or full-reload events that broke the earlier `httpServer.close`-tied teardown. Symbol.for guard keeps the install idempotent across server restarts within a session. Removes: - Module-load-time install + argv[2] === "dev" check - VITEST / build env-var negative skip list Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(dev): narrow gate to !isPreview so vite preview skips install `command === "serve"` covers both `vite dev` and `vite preview` (the post-build static server). Preview doesn't stream RSC and doesn't need this guard, so narrow to `command === "serve" && !env.isPreview`. `vinext start` runs prod-server.ts directly without Vite, so it was already correctly excluded — `config()` never fires there. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: extend socket-error backstop to vinext start (Next.js parity) Next.js installs uncaughtException + unhandledRejection handlers in their router-server unconditionally — no dev/prod gate. Both the Node.js dev server and the Node.js prod server share the same process-level error guards. See vercel/next.js packages/next/src/server/lib/router-server.ts:809-810. vinext was only guarding the dev path. `vinext start` runs prod-server.ts directly as a Node HTTP server (used for self-hosted deploys; Cloudflare Workers prod doesn't load this module — the runtime owns socket lifecycle there) and had the same theoretical exposure to peer-disconnect crashes through the pipeline() / fetch() paths it streams responses through. Refactor: - Extract the install function from index.ts into a new src/server/socket-error-backstop.ts (drop the "Dev" prefix — no longer dev-only). - Keep the call from the vinext:config plugin's config() hook, gated on command === "serve" && !isPreview (covers vinext dev / vp dev / vite dev / library embedders). - Add a parallel call at the top of startProdServer() in prod-server.ts (covers vinext start). vinext is more conservative than Next.js's log-only handler — we filter strictly on peer-disconnect codes and sync re-throw the rest, so genuine bugs still surface. The parity is in *where* we install, not what we swallow. Vitest workers and `vinext build` never reach either entry point, so peer-disconnect errors in those contexts surface normally. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(dev): auto-install socket-error backstop at module load The Vite config() hook gate (`command === "serve" && !isPreview`) proved unreliable in vite-plus's lifecycle — the hook didn't fire (or didn't pass command correctly), and install was silently skipped. Field reproducer: published |