$npx -y skills add vercel/next.js --skill next-cache-components-optimizerDrive a Next.js route to instant navigation by setting up an agentic loop, under Cache Components / PPR, on initial load (hard navigation) and client-side navigation (soft navigation). Encode the goal as a failing @next/playwright instant() e2e and work it to green, one verified
| 1 | # next-cache-components-optimizer |
| 2 | |
| 3 | Set up an agentic optimization loop that drives a Next.js route from "not |
| 4 | instant" to "instant" and keeps it there. The loop is test-driven: encode the |
| 5 | goal as a failing `@next/playwright` `instant()` test, work it to green, and |
| 6 | ship the test as the regression guard. Run it once per target route. Work the |
| 7 | phases P → G in order; each ends in a gate. Fix recipes live in two lazily-read |
| 8 | references — `reference/patterns.md` (before→after for each blocker type) and |
| 9 | `reference/real-app-patterns.md` (parallel routes, auth gates, the empty-shell |
| 10 | and responsive-skeleton failure modes). Read one only when its phase points |
| 11 | there. |
| 12 | |
| 13 | ## What is invariant, and what is yours |
| 14 | |
| 15 | One thing here is fixed. The rest is yours. Read this before treating any |
| 16 | command, platform, or env var below as a requirement. |
| 17 | |
| 18 | - **Invariant: the verification loop.** Maximizing the shell is worthless |
| 19 | unless you can prove it. The proof is an automated check: under a lock that |
| 20 | gates dynamic data, the static shell still commits. RED shows the gap, GREEN |
| 21 | shows it closed, the test ships as the regression guard. It must run on a |
| 22 | production-like build and must not be able to pass vacuously. Stand the loop |
| 23 | up once; every later optimization is then verifiable by construction. The |
| 24 | loop is the deliverable, not any one route. |
| 25 | - **The mechanism: `@next/playwright` `instant()`.** This skill locks with |
| 26 | [`instant()`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config/instant#testing-instant-navigation): |
| 27 | a ruler, not a stopwatch (phase A). It comes from |
| 28 | `@next/playwright` (installed alongside `@playwright/test`, on the same |
| 29 | release line as `next`), so it isn't tied to any host. Keep it. Timing a |
| 30 | navigation by hand is too flaky to trust, and is the failure mode this skill |
| 31 | exists to prevent. |
| 32 | - **Yours: the rig.** How you build, deploy, authenticate, configure |
| 33 | Playwright, and loop belongs to your stack, not to this skill. A local |
| 34 | `next build && next start`, a CI/staging container, and a per-push preview |
| 35 | deploy are equally valid rigs; the verdict comes from the build, never the |
| 36 | platform. Phase 0 maps the invariant onto your repo. Read every platform |
| 37 | name, env-var spelling, and command below as an example to translate, not a |
| 38 | requirement. |
| 39 | |
| 40 | ## Two navigations, two loading states |
| 41 | |
| 42 | A route reaches the user two ways, and both must be instant: |
| 43 | |
| 44 | - **Initial load (hard navigation)** commits the route's prerendered static |
| 45 | shell; deferred parts stream in behind their loading skeletons (Suspense |
| 46 | fallbacks, `loading.tsx`). |
| 47 | - **Client-side navigation (soft navigation)** commits the destination's |
| 48 | prefetched App Shell — the `<Link>` default under Partial Prefetching — |
| 49 | re-rendering only the segments that change. |
| 50 | |
| 51 | The fix patterns are identical for both; the test differs only in how the |
| 52 | navigation is driven ("Driving the navigation in tests" below). The two shells |
| 53 | can differ; guard the one you ship, both when both matter |
| 54 | (`reference/real-app-patterns.md`). |
| 55 | |
| 56 | ## Goal |
| 57 | |
| 58 | Maximizing the static shell is the optimization objective: the most meaningful |
| 59 | prerendered content commits immediately, and only genuinely per-request data |
| 60 | streams in afterward. The shipped test deterministically encodes **present ∧ |
| 61 | instant**; **non-blank** is the additional bar the workflow enforces by |
| 62 | judgment (D1/D2/E), because an `instant()` pass alone is satisfied by a blank |
| 63 | `fallback={null}` shell (the empty-shell failure mode, |
| 64 | `reference/real-app-patterns.md`). |
| 65 | |
| 66 | `instant()` is a ruler, not a stopwatch: assert that the shell appears under |
| 67 | the lock; do not time it. A trustworthy verdict requires a production build |
| 68 | (phase A). |
| 69 | |
| 70 | The GREEN under the lock is the deterministic verdict; each gate keeps it |
| 71 | trustworthy. |
| 72 | |
| 73 | ## Reporting to the user |
| 74 | |
| 75 | This loop is meant to run unattended — ideally across many navigations in one |
| 76 | pass — so it doesn't stop to ask after each route. What matters is how you word |
| 77 | and present the results, not how often you interrupt. The mechanics below — the |
| 78 | rig, RED, GREEN, the gates — are your scaffolding; the user never needs to hear |
| 79 | those words. |
| 80 | |
| 81 | - **Speak their language.** Descri |