From 583fb865380f4fa92144daed613ec7c4b29de09d Mon Sep 17 00:00:00 2001 From: Steve Faulkner Date: Tue, 3 Mar 2026 10:27:34 -0600 Subject: [PATCH] docs: add field learnings from real migrations to skill docs Add practical tips learned from real-world vinext migrations: - Field learnings section in SKILL.md (auth guards, server actions, optimizeDeps, error boundaries, dev warnings) - Known-safe migration checklist in config-examples.md - New troubleshooting entries for common regressions - Auth + session stability guide for App Router Based on PR #233 by @vorcigernix, rebased on current main. --- .agents/skills/migrate-to-vinext/SKILL.md | 17 +++++++ .../references/config-examples.md | 49 +++++++++++++++++++ .../references/troubleshooting.md | 12 +++++ 3 files changed, 78 insertions(+) diff --git a/.agents/skills/migrate-to-vinext/SKILL.md b/.agents/skills/migrate-to-vinext/SKILL.md index 5a921e39..eade3a6b 100644 --- a/.agents/skills/migrate-to-vinext/SKILL.md +++ b/.agents/skills/migrate-to-vinext/SKILL.md @@ -190,6 +190,23 @@ See [references/troubleshooting.md](references/troubleshooting.md) for common mi | `runtime` / `preferredRegion` | Route segment configs ignored | | PPR (Partial Prerendering) | Use `"use cache"` directive instead (Next.js 16 approach) | +## Field Learnings (From Real Migrations) + +1. Auth/session behavior can regress even when pages appear to load. + - In request-wide auth guards (`proxy.ts` / middleware equivalents), treat vinext static asset paths (`/assets/*`) as internal like `/_next/*`. Redirecting these to sign-in breaks anonymous/public rendering. + - When calling auth APIs server-side, do not rely only on `headers()`. Merge cookie-store cookies into the request headers so RSC/server-action paths consistently see session cookies. + - For any DB-backed auth stack, use persistent/shared storage (not in-memory) and ensure required schema exists before first request. Keep stack-specific details in troubleshooting docs. +2. Avoid server actions for high-frequency client mutations. + - If a UI action creates many records (for example AI parsing into many day/category entries), use one route handler (`/api/...`) batch request instead of looped server actions. + - Reason: server actions trigger RSC replay and layout re-execution; with auth-protected layouts this can surface `NEXT_REDIRECT` noise and UX churn. This pattern also applies to Next.js generally, but often becomes more visible during migration. +3. Be careful with `optimizeDeps.exclude`. + - Excluding broad component libraries can cause ESM/CJS runtime mismatches (for example `react/jsx-runtime` named export errors in dev). + - Prefer default optimization unless there is a proven incompatibility. +4. Route segment `error.tsx` can expose shim/runtime gaps. + - If adding segment error boundaries triggers runtime import errors from vinext shims, remove that segment `error.tsx` and rely on the nearest parent or root error boundary until upstream fix is available. +5. Some dev warnings are plugin/internal noise. + - Example: ` must have a valid as value` can be emitted by current RSC tooling and may be non-blocking. + ## Anti-patterns - **Do not modify `app/`, `pages/`, or application code.** vinext shims all `next/*` imports — no import rewrites needed. diff --git a/.agents/skills/migrate-to-vinext/references/config-examples.md b/.agents/skills/migrate-to-vinext/references/config-examples.md index 90f52573..9f0e0fbf 100644 --- a/.agents/skills/migrate-to-vinext/references/config-examples.md +++ b/.agents/skills/migrate-to-vinext/references/config-examples.md @@ -186,6 +186,55 @@ Nitro auto-detects the platform in most CI/CD environments, so the `NITRO_PRESET | `appDir` | `string` | project root | Custom base directory for `app/` and `pages/` | | `rsc` | `boolean` | `true` | Auto-register `@vitejs/plugin-rsc` for App Router | +## Known-Safe Migration Checklist (App Router) + +Use this checklist to avoid common real-world regressions during vinext migration. + +### 1) Auth guard must bypass vinext assets + +If you use request-wide auth (`proxy.ts`), treat `/assets/*` as internal/static just like `/_next/*`. + +```ts +function isInternalRequest(request: Request): boolean { + const pathname = new URL(request.url).pathname; + if (pathname.startsWith("/_next/")) return true; + if (pathname.startsWith("/assets/")) return true; // vinext static assets + if (request.headers.has("rsc")) return true; + if (request.headers.has("next-action")) return true; + return false; +} +``` + +### 2) Prefer API route handlers for high-volume client mutations + +Avoid looped server actions for workloads like "AI parsed N entries". + +Use: +- one client request to `/api/.../batch` +- server-side validation/auth in the route +- one batch write/update flow + +```ts +// client +await fetch("/api/dashboard/work-blocks/batch", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ entries }), +}); +``` + +### 3) Keep dependency optimization defaults unless proven otherwise + +Do not broadly add libraries to `optimizeDeps.exclude` unless you have a verified reason. +This can trigger ESM/CJS runtime mismatches in dev. + +### 4) Better Auth + SIWE should use persistent/shared DB + +For SIWE nonce verification reliability: +- use shared DB-backed auth storage +- ensure Better Auth tables exist (`verification` in particular) +- run explicit bootstrap migration scripts rather than relying on per-request introspection + ## vinext deploy flags | Flag | Description | diff --git a/.agents/skills/migrate-to-vinext/references/troubleshooting.md b/.agents/skills/migrate-to-vinext/references/troubleshooting.md index d25705eb..6f1b217f 100644 --- a/.agents/skills/migrate-to-vinext/references/troubleshooting.md +++ b/.agents/skills/migrate-to-vinext/references/troubleshooting.md @@ -11,6 +11,9 @@ | `vinext: command not found` | vinext not installed or not in PATH | Install vinext: `npm install vinext`, then run via `npx vinext` or package.json scripts | | RSC environment crash on dev start | Native Node module (sharp, satori) loaded in RSC env | vinext auto-stubs these in production; in dev, ensure these are only imported in server code behind dynamic `import()` | | `ASSETS binding not found` | wrangler.jsonc missing assets config | Add `"assets": { "not_found_handling": "none" }` to wrangler.jsonc | +| `NEXT_REDIRECT` during/after server action | Mutation implemented as server action triggers RSC replay + auth-protected layout re-exec | Move high-volume mutations to route handlers (`/api/...`) and batch writes in one request | +| `The requested module '/node_modules/react/jsx-runtime.js' does not provide an export named 'jsx'` | Dependency optimization/shim mismatch (often after `optimizeDeps.exclude` changes) | Remove broad `optimizeDeps.exclude` entries and restart dev with fresh Vite cache | +| Public pages lose CSS/JS when logged out | Request guard redirects vinext assets | Treat `/assets/*` as internal/static in auth guard matcher and bypass auth redirects | ## ESM Conversion Issues @@ -34,6 +37,15 @@ Alternatively, convert these files to ESM (`export default` syntax) and keep the **Cause:** These are Pages Router APIs. They only work in `pages/`, not `app/`. **Fix:** This is expected Next.js behavior, not a vinext issue. +## Auth + Session Stability (App Router) + +- If using `proxy.ts` auth gating, include vinext assets (`/assets/*`) in the internal/public bypass list. +- In server-side auth helpers, merge cookie-store cookies into request headers before calling auth session APIs. +- For Better Auth with SIWE: + - use persistent/shared DB storage + - ensure schema bootstrap includes Better Auth tables (especially `verification`) + - avoid running migration introspection on every request; run explicit bootstrap migrations instead + ## Cloudflare Deployment Issues **Symptom:** Build succeeds but deploy fails with worker size errors.