mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
vinext@0.1.7
14 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
33be48648d |
fix(script): register src beforeInteractive scripts and mark hoisted output (#2019)
## Summary - Register `beforeInteractive` Scripts with `src` through BeforeInteractiveContext so they are hoisted into <head> ahead of interactive, exactly like the inline form (previously they bypassed the registry and rendered in source order, after React Float's head content). - Suppress the client React render for both inline AND src beforeInteractive Scripts in the App Router so the hoisted tag is never duplicated. - Tag every hoisted script with Next.js's `data-nscript="beforeInteractive"` marker. - Map `crossOrigin` -> `crossorigin` and `referrerPolicy` -> `referrerpolicy` on hoisted scripts (parity with Next.js set-attributes-from-props). - Extract `renderBeforeInteractiveInlineScripts` into a dedicated, pure module (before-interactive-head.ts) so the emit path is unit-testable. ## Root Cause The beforeInteractive SSR branch computed `inlineContent = src ? null : ...` and only registered when `inlineContent !== null`, so any Script with a `src` was never captured by the registry and never spliced into <head>; it stayed where the user wrote it, behind React Float's hoisted resource hints, defeating the before-interactive guarantee. Hoisting src scripts then requires the client to stop rendering them through React (the React-created <script> never executes and would only add a duplicate DOM node), so the client dedupe condition is aligned with the SSR registration condition. The hoisted output also lacked Next.js's `data-nscript` marker, and REACT_TO_HTML_ATTR omitted crossOrigin/referrerPolicy, so those attribute names did not match Next.js's lowercased output. ## References - Fixes #2016 - Next.js: .nextjs-ref/packages/next/src/client/script.tsx (data-nscript, src/inline registry parity), set-attributes-from-props.ts (lowercased attrs) - Ported: test/e2e/app-dir/script-before-interactive/script-before-interactive.test.ts ## Verification - CI=true pnpm test tests/script.test.ts tests/script-head-ordering.test.ts tests/nextjs-compat/script-nonce.test.ts tests/shims.test.ts -> 1139 passed - CI=true npx vp check on all changed files -> pass Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
cd181cc755 | chore: add codex to gitignore (#1992) | ||
|
|
835e6b9943 |
fix(app-router): suppress redirect console errors in production onCaughtError (root-layout-redirect) (#1878)
* fix(app-router): suppress redirect console errors in production onCaughtError (#1830) When redirect() is called from a 'use client' root layout (or any client component), React catches the NEXT_REDIRECT sentinel via RedirectErrorBoundary and then calls the hydrateRoot onCaughtError callback. In dev mode vinext already filtered these via devOnCaughtError, but the production path had no onCaughtError at all — React's built-in fallback calls console.error, producing a spurious browser console error that fails the Next.js compat test assertion `expect(foundErrors).toBe(false)`. Fix: add prodOnCaughtError to app-browser-error.ts that silently drops navigation signal errors (NEXT_REDIRECT, NEXT_NOT_FOUND, NEXT_HTTP_ERROR_FALLBACK) and logs all other caught errors, preserving React's default behavior. Add fixture tests/fixtures/root-layout-redirect/ (dedicated 'use client' root layout with redirect()) and Playwright project root-layout-redirect (port 4184) with spec porting the Next.js root-layout-redirect > should work using browser. Part of #1830 * fix: include result/ page in root-layout-redirect fixture * fix: add lockfile entry for root-layout-redirect fixture, use prod server, import isNavigationSignalError Three fixes to unblock catastrophically-failing CI: 1. pnpm-lock.yaml: Add missing importer entry for tests/fixtures/root-layout-redirect. The fixture was added without updating the lockfile, causing ERR_PNPM_OUTDATED_LOCKFILE on every CI job during `vp install`. 2. playwright.config.ts: Switch the root-layout-redirect server from `npx vp dev` (dev mode) to `vinext build + vinext start` (production mode). The fix under test — prodOnCaughtError — is only active in production builds; running in dev mode exercised the pre-existing devOnCaughtError path and never touched the new code. 3. app-browser-error.ts: Replace the inline isNavigationSignalDigest helper with an import of isNavigationSignalError from utils/navigation-signal.ts. The module is dependency-free and already in the production browser bundle; inlining it reintroduced the drift risk that navigation-signal.ts was created to prevent. Addresses ask-bonk findings: blocking (test ran in dev mode) and maintainability (inline classifier duplication). * test: add prodOnCaughtError unit tests, run root-layout-redirect e2e in CI, scope gitignore negation |
||
|
|
f27c40a77f |
chore: split e2e compatibility by App Router vs Pages Router (#1321)
* feat(compat): split e2e compatibility by App Router vs Pages Router
The /compatibility page previously showed one undifferentiated grid of
~1000 Next.js test files. This change classifies each test by which
router(s) its fixture exercises (App, Pages, both, or unknown) and
surfaces the breakdown in the UI.
How:
- A new `router` column on `compat_file_results` (enum: app | pages |
both | unknown). Defaults to 'unknown' so pre-classifier rows still
render — they just show up under 'Other'.
- A new `scripts/classify-nextjs-suites.mjs` walks each test's fixture
directory and looks for app/page.tsx, app/route.ts, app/layout.tsx,
pages/*.tsx (excluding _app / _document / _error specials). A fixture
with real routes in both folders is classified as 'both' — these are
the genuine parity tests and counting them only once would hide a
router-specific failure.
- Edge cases handled in the classifier:
* pageExtensions naming (layout.page.tsx → layout)
* Suites whose .test.ts lives in a test/ subdir alongside the fixture
* Inline-fixture suites under test/e2e/app-dir/ (no on-disk routes,
but path convention says App Router)
* APP_ROUTER_NON_APP_DIR_SUITES curated override
* Skips node_modules and .next when scanning fixtures
- The nightly workflow now runs the classifier in the build job once
per run (the cheap part — happens with Next.js still on disk),
uploads the suite → router map as an artifact, and the report job
joins it into the ingest payload before POSTing.
- The compatibility page gains a 'By router' card row showing per-router
pass rates and file counts (parity tests are counted toward both
router buckets — adding them exceeds the total, see the explainer
card). The contribution grid grows filter chips above it for
interactive narrowing.
Verified:
- vp check (format + type + lint) clean
- 14 new classifier unit tests pass (vp test run tests/classify-nextjs-suites.test.ts)
- apps/web build:vinext succeeds end-to-end
- Local classifier run against .nextjs-ref reports
app=576 / pages=325 / both=113 / unknown=22 out of 1036 suites, with
spot-checked classifications matching expectations.
Backward compatibility: the ingest endpoint treats `router` as optional;
existing workflow runs and historical rows continue to function and
render as 'Other' until the next nightly classifies them.
* refactor(compat): store router classification in its own table
Replaces the inline `router` column on `compat_file_results` (introduced
in the previous commit) with a dedicated `compat_suite_meta` table,
classification keyed by `suite`. The /compatibility UI LEFT JOINs the
two tables at query time.
Rationale (per design discussion in PR #1321):
- Classifications conceptually describe test files, not test runs. Storing
them per-row coupled their cadence to results ingestion, which is wrong
when (a) the Next.js ref bumps and re-classifies everything, (b) an
override fix lands without re-running tests, or (c) a partial test run
still wants fresh classifications.
- One row per suite (PK on `suite`) means re-classifying is an upsert,
not a backfill loop. Provenance (`next_ref`, `classified_at`) is
stored on the row for debugging.
- Decoupling lets the workflow POST classifications from the build job
immediately after running the classifier, without round-tripping through
the report job. Results ingestion stays focused on results.
Endpoints:
- `POST /api/compatibility` no longer accepts `router` per file
(reverted to its pre-PR shape).
- `POST /api/compatibility/classify` (new): accepts
`{ nextRef, classifiedAt?, suites: [{ suite, router }] }`,
upserts in chunks (25 rows per INSERT to fit SQLite's variable cap),
shares auth with the results endpoint via a new `_auth.ts` helper.
Workflow:
- The build job now POSTs the classification map directly to the new
endpoint after running the classifier. Same guardrails as the results
POST (only full-suite, only against main).
- The report job no longer needs to download / merge the classification
artifact — it's already in D1 by the time results land.
- The classification JSON is still uploaded as a workflow artifact for
manual re-submission / debugging.
Schema:
- New table `compat_suite_meta(suite PK, router, next_ref, classified_at)`
with an index on `router` for the per-router count queries.
- `compat_file_results` reverts to its pre-PR columns. No data migration
needed because the column was only ever populated on this branch.
Trade-off: classification changes are now retroactive — re-classifying a
suite updates how it appears in every historical run. This is usually
what you want (corrections heal the whole history) but means the trend
chart isn't a strict point-in-time record. The provenance fields on the
meta row let you tie a reclassification back to a specific Next.js ref.
Verified:
- vp check clean
- 14 classifier unit tests still pass
- apps/web build:vinext succeeds; /api/compatibility/classify shows up
in the route list
* refactor(compat): drop redundant next_ref from compat_suite_meta
The Next.js ref a classification was produced against is already
recoverable from the run history — compat_runs records next_ref per
run, and the most recent classification's ref is implicit (it's the
ref of the most recent classify POST, which the workflow always pairs
with a run).
The future-proofing case for per-ref classifications would want a
composite (suite, next_ref) PK rather than a single global row anyway,
so this column doesn't help with that scenario either. classified_at
is enough for the debug case ('when was this last computed?').
Changes:
- Drop next_ref column from compat_suite_meta (3 columns now:
suite PK, router, classified_at)
- /api/compatibility/classify no longer requires nextRef in the body
- Workflow no longer passes NEXT_REF when building the classify payload
- Migration regenerated as 0001_romantic_skullbuster.sql (one fewer
column on the CREATE TABLE)
- Chunk size bumped to 33 rows/INSERT (100-var cap / 3 columns)
Verified: vp check clean, classifier tests pass, apps/web build succeeds.
* feat(compat-ui): share router filter between grid and trend chart
Lifts the router-filter state out of ContributionGrid into a new
CompatibilityViews client wrapper that owns the Kumo segmented Tabs
control. The grid and the line chart both consume the active filter
as a prop, so changing the tab updates both visualisations in lockstep.
The line chart now plots per-router series. The trend query was
rewritten to aggregate via JOIN against compat_suite_meta — one row
per run with app/pages/both/unknown rollups in a single round-trip,
~90 runs × ~1000 file rows over an indexed join. The TrendPoint
carries all five series; the chart picks one based on the filter
without re-fetching.
Other UI tweaks in this commit:
- Replaced the hand-rolled pill row with Kumo Tabs (variant='segmented',
size='sm'). Fixes a weird active state (bg-kumo-default + text-kumo-base
was using the text color for backgrounds, producing a saturated
inversion).
- 'Parity' → 'Mixed' in user-visible labels. Internal identifiers
(DB enum 'both', bucket variable 'parity') unchanged.
- Removed the standalone 'Other' stat card; the segmented Tabs still
expose the 'Other' filter so unclassified suites are reachable.
- Reorganised the page into one 'Test files and trend' section
containing both visualisations, gated by the shared Tabs.
- .gitignore: ignore .dev.vars (Wrangler's local-secrets convention)
so the COMPAT_INGEST_SECRET we use for local testing never gets
committed by accident.
Verified:
- vp check clean (format + type + lint)
- 14 classifier unit tests pass
- apps/web build:vinext succeeds; both API endpoints + page render
* fix(compat): address PR review comments
Addresses actionable items from the two /bigbonk review passes:
1. scanFixture: skip recursion into already-checked app/ and pages/
(with a wrinkle around fixture wrappers).
The previous code unconditionally pushed every child onto the walk
stack, which (a) wasted work re-walking subtrees the route checker
already covered and (b) risked a false positive on App Router route
groups literally named 'pages' (e.g. app/pages/index.tsx would have
tripped the Pages Router detector).
Naive fix (skip descent into any app/ or pages/) regressed ~10 real
Next.js fixtures that use a wrapping directory literally named 'app'
as the test app's project root, with the real app/ and pages/ nested
inside (test/e2e/og-api, test/e2e/middleware-static-files, etc.).
Final fix: a directory named app or pages is treated as a fixture
wrapper (and recursed into) if it contains a top-level next.config.*
OR an inner app/ alongside an inner pages/. Otherwise it's handed to
the route checker, which either finds real routes or returns nothing
and the walk skips it. The wrapper detector intentionally does NOT
treat middleware.{js,ts} as a wrapper signal, because Next.js tests
put noop middleware.js files inside real App Router app/ to assert
the file is ignored at that level (test/e2e/app-dir/app-middleware).
Verified against the full test/e2e/ tree of the local Next.js
checkout: 1036 suites classify identically to the pre-fix output
(576 app / 325 pages / 113 both / 22 unknown), with the
app/pages/index.tsx false-positive now correctly handled.
2. list-nextjs-e2e-suites.mjs: add the same import.meta.url guard the
classifier already has, so importing the module programmatically
doesn't immediately parse process.argv and write a file.
3. _auth.ts: early-exit when the X-Compat-Secret header is missing
or empty, before paying two SHA-256 digests. The constant-time
guarantee we care about (don't leak the contents of the expected
secret via length or prefix matching) is preserved — we only
short-circuit on values we already know can't match a non-empty
secret.
4. Migration 0001_romantic_skullbuster.sql: add trailing newline.
Tests:
- 3 new regression tests added (18 total, all pass):
* fixture wrapper with next.config.js + inner app/ + pages/
* fixture wrapper with next.config.js + inner pages/ only
* App Router app/ containing a route group named 'pages'
* App Router app/ containing a noop middleware.js
- vp check clean
- Classifier output diff against current Next.js HEAD: empty
* fix(compat-ui): unexport cellMatchesFilter (knip)
CI's knip step flagged `cellMatchesFilter` as an unused export. It's only
used inside contribution-grid.tsx itself — the shared wrapper has its
own bucketing logic in compatibility-views.tsx. Drop the `export`.
* fix(compat): address third-pass review comments
1. sqlExcluded: narrow parameter type to a closed union
("router" | "classified_at") so the no-user-input invariant for
sql.raw is compiler-enforced rather than relying on a code comment.
2. ContributionGrid: gate the SVG render on visibleCells.length > 0,
and also clamp svgWidth/svgHeight to >= 0. Previously, when a
filter emptied the grid, the SVG rendered with width=-3/height=-3
alongside the placeholder div (browsers clamped silently but it
was invalid SVG).
3. compatibility/page.tsx 'How this works' card: add a short note
that per-router trend lines use the latest classification, so
reclassifying a suite updates how it appears in historical runs.
The aggregate "All" line is unaffected. Avoids a confusing
support question if users notice old per-router numbers shift
after a classifier improvement.
4. scanFixture readability: simplify the early-return checks from
'if (hasApp && hasPages)' to 'if (hasPages)' / 'if (hasApp)',
since the other flag was just set on the line above. No
behavioural change; classifier output against the full Next.js
test/e2e tree is byte-identical (1036 suites, 576/325/113/22).
5. /api/compatibility/classify body validator: bounds-check
classifiedAt. Reject NaN/Infinity and any timestamp earlier
than 2023-01-01 UTC. Catches the common seconds-vs-milliseconds
mistake and accidental 0/-1 values from buggy callers. The
only legitimate caller (the GH workflow) sends Date.now() so
this is purely defensive.
Verified:
- vp check clean (format + type + lint + knip)
- 18 classifier unit tests pass
- apps/web build:vinext succeeds
- Classifier output against current Next.js HEAD is unchanged
* refactor(compat-ui): extract shared router bucketing module
Addresses items 1, 3, and 4 from the fourth review pass.
1. Trend GROUP BY note (item 1): added an inline comment explaining
that selecting r.created_at while grouping by r.id only is a SQLite
functional-dependency affordance. Standard SQL (postgres etc.)
would reject it; the comment heads off a future 'fix' that breaks
the query if it's ever ported.
2. Unified router bucketing (item 3): the three places that sliced
cells by router filter all used slightly different naming
conventions ('parity' vs 'both', 'other' vs 'unknown'). Extracted
the canonical logic to a new ./router-buckets module with one
shared vocabulary (the same as RouterKind), and updated all three
call sites:
- contribution-grid.tsx: cellMatchesFilter from shared module
- compatibility-views.tsx: countByFilter for tab labels
- page.tsx: bucketByRouter + bucketPassRate for stat cards,
byRouter.parity/other renamed to byRouter.both/unknown
Doc comment at the top of router-buckets.ts pins the
'Mixed counts in both app and pages' rule in one place. No
behavioural change.
3. passRate function rename (item 4): renamed the line chart's local
ratio helper from passRate -> computePassRateRatio to avoid
shadowing the passRate variable in page.tsx (and to distinguish
it from bucketPassRate in router-buckets which returns a
percentage, not a ratio).
Not addressed (intentionally):
- 'Mixed (both)' vs 'Parity'/'Interop' label (item 2): the user
explicitly chose 'Mixed' over 'Parity' in an earlier message.
- trendRowsDesc rename (item 5): reviewer self-tagged 'very minor';
renaming would muddle the diff.
- deriveSuiteGroup inconsistent levels (item 5b): pre-existing
tooltip-only behaviour, not introduced by this PR.
Verified:
- vp check clean (format + type + lint + knip)
- 18 classifier unit tests pass
- apps/web build:vinext succeeds
|
||
|
|
2acec092be | chore: add next-env.d.ts to .gitignore (#1224) | ||
|
|
747bb0ec76 |
ci: add Next.js deploy suite harness (#1189)
* ci: add Next.js Pages Router deploy suite harness Add the workflow, scripts, and manifest generator for running the Next.js Pages Router deploy test suite against vinext. Triggers: - Nightly cron (06:00 UTC) against main - Manual dispatch with configurable vinext-ref, next-ref, and concurrency Extracted from #922. * refactor: align deploy suite harness with Next.js adapter testing docs - Rename scripts to match Next.js convention: e2e-deploy.sh, e2e-logs.sh, e2e-cleanup.sh - Split workflow into build + test jobs (build once, shard 16 ways) per the documented adapter testing pattern - Generalize workflow from pages-only to configurable: add suite-filter input (pages/app/all, defaults to pages) - Add --filter flag to manifest generator (replaces the pages-hardcoded version) - Accept ADAPTER_DIR (Next.js docs convention) alongside VINEXT_DIR - Rename workflow file to nextjs-deploy-suite.yml - Use matrix.group strings ("1/16") instead of shard integers, matching the docs example * ci: default suite-filter to app * ci: bump Next.js default to v16.2.6, move cron to 02:00 UTC * address review: add report job, clean up cache paths, document compat shims - Add a report job that aggregates .results.json across all shards into a GitHub Actions summary (pass/fail/skip counts, failed test details, passed suite list) and uploads a JSON report artifact - Upload test results from every shard (not just on failure) - Remove redundant next.js/ from cache paths (already under .) - Add comment explaining why IS_TURBOPACK_TEST=1 is needed - Clean up stale PID file in e2e-cleanup.sh - Add header comments to all scripts explaining their purpose and contract - Document the hardcoded warning messages and .next/trace shim - Document the YAML catalog parser assumptions - Fix [[ ]] -> [ ] inconsistency in run-nextjs-deploy-suite.sh * ci: add temporary PR trigger to test workflow [remove before merge] * fix: address deploy script failures found in CI and local testing Bugs found and fixed: - IMMUTABLE_ASSET_TOKEN marker renamed to NEXT_SUPPORTS_IMMUTABLE_ASSETS to match what next-deploy.ts parseIdsFromCliOuput() actually parses. Without this, every test fails with 'Failed to get supportsImmutableAssets'. - Deploy script now injects "type": "module" into test app package.json and generates a vite.config.ts. Without type:module, Rolldown emits .mjs files but the RSC plugin's cross-environment imports expect .js. This mirrors what `vinext init` does (steps 3 and 5). - Added vp (Vite+) fallback to run_pnpm() for environments where pnpm and corepack are not available but vp is. - Cleanup script now uses process group kills (kill -TERM -PID) and a port-based lsof fallback to handle orphaned child processes from vp/pnpm exec wrappers. - Error cleanup trap now dumps the last 80 lines of the build log and last 40 lines of the server log to stderr, so failures are visible in CI output (previously only showed file sizes). - Test job uses run-install: false since the workspace is already built in the cache from the build job. Tested locally: deploy script succeeds, curl returns valid HTML, logs script outputs all three required markers (BUILD_ID, DEPLOYMENT_ID, NEXT_SUPPORTS_IMMUTABLE_ASSETS), cleanup kills the server. * fix: use vinext init in deploy script, add next.config.js to CJS rename list Replace the manual type:module / vite.config.ts / CJS rename logic in e2e-deploy.sh with a single `vinext init --skip-check --force` call. This runs after pnpm install (so deps are available) and before vinext build. Also add next.config.js to the CJS_CONFIG_FILES list in project.ts. Without this, vinext init adds type:module but doesn't rename CJS next.config.js files, causing 'module is not defined in ES module scope' errors. This was the root cause of the CI failures — Next.js test fixtures use module.exports in next.config.js. All 61 init tests pass. * fix: convert CJS next.config.js to ESM instead of renaming to .cjs Next.js doesn't support next.config.cjs, so we can't rename it. Instead, convert module.exports/require() to export default/import in-place after vinext init adds "type": "module". Also revert adding next.config.js to CJS_CONFIG_FILES — vinext init should not rename it since it's not a generic config file. Tolerate pnpm 10+ ERR_PNPM_IGNORED_BUILDS exit code 1 on install (the install completes, packages are in node_modules, but pnpm exits non-zero due to unapproved build scripts). Verify node_modules/vinext exists as a safety check. Tested against the real Next.js actions-streaming fixture: CJS next.config.js converted, app builds, server starts, HTTP 200. * fix: emit both IMMUTABLE_ASSET_TOKEN and NEXT_SUPPORTS_IMMUTABLE_ASSETS v16.2.x parses IMMUTABLE_ASSET_TOKEN, canary renamed it to NEXT_SUPPORTS_IMMUTABLE_ASSETS. Emit both for cross-version compat. * fix: enable JSX in .js files, convert CJS next.config.ts to ESM Add vinext:jsx-in-js transform plugin to handle JSX in plain .js files. Next.js allows JSX in .js files (Babel/SWC handle it transparently), but Vite 8's built-in vite:oxc plugin excludes .js files by default (exclude: /\.js$/) AND infers lang: 'js' from the extension (which disables JSX parsing). Neither can be fixed via config alone. The plugin runs with enforce: 'pre' before vite:oxc, transforming .js files with OXC using lang: 'jsx' so JSX is compiled before vite:oxc sees the code. This unblocks ~60 test suites in the deploy suite. Also extend the deploy script's CJS-to-ESM config converter to handle next.config.ts files (not just .js), fixing ~6 more test failures. Tested: 1284 tests pass (jsx-in-js + shims + routing + app-router), zero regressions. * ci: trigger clean workflow run * fix: improve CJS-to-ESM converter for next.config files The naive regex converter missed two patterns: - require('mod')(args) produced invalid ESM (import X from 'mod'(args)) - require() calls inside function bodies were not converted New converter handles: - module.exports = X → export default X - const X = require('mod') → import X from 'mod' - const X = require('mod')(args) → import _X from 'mod'; const X = _X(args) - require('mod') in expressions → (await import('mod')).default Tested against bundle-analyzer, path, and inline require patterns. * . * Apply suggestion from @james-elicx * fix: handle destructured requires in CJS converter, read port from file in cleanup - Add pattern for const { a, b } = require('mod') → import { a, b } from 'mod' - Read port from PORT_FILE in cleanup_on_error trap instead of using $PORT variable which may be unset if the script fails before port allocation - Add TODO noting remaining CJS edge cases (dynamic require, require.resolve) * Apply suggestions from code review Co-authored-by: James Anderson <james@eli.cx> * Apply suggestion from @james-elicx |
||
|
|
ef1943ce5d | chore: add more gitignore entries (#725) | ||
|
|
a6d2c3a09c |
Refactor App Router virtual entries into typed runtime modules (#616)
* refactor: move app router SSR/browser runtime into typed modules * style: format typed app runtime modules * refactor: address runtime entry review follow-ups |
||
|
|
3af644f5e9 |
docs: strengthen Next.js parity verification in agent guidelines (#604)
Add mandatory Next.js behavior verification for all bug fixes and security work, not just feature development. We repeatedly shipped fixes that diverged from Next.js because this step was skipped (config header execution order, javascript: URI blocking, ISR cache key semantics). Changes: - Add local Next.js clone instructions (.nextjs-ref, gitignored) for fast ripgrep searches of source and test suite - Add 4-step verification checklist to Fixing Bugs section - Require documenting what Next.js does in PRs and issue closures - Update Looking at Next.js Source with clone instructions - Add .nextjs-ref/ to .gitignore |
||
|
|
764a496ce7 |
add oxfmt formatter (#380)
* add oxfmt formatter: config, scripts, CI, editor setup, docs * rebuild lockfile * fix: add Format to required checks list, remove dead ignore pattern * run fmt * add format to agents.md again |
||
|
|
a78266481b |
feat: support export const revalidate on App Router GET route handlers (#320)
* chore: add .worktrees/ to gitignore * feat: support `export const revalidate` on App Router GET route handlers Read the route segment config `revalidate` from route handler modules and set `Cache-Control: s-maxage=N, stale-while-revalidate` on GET responses, matching Next.js behavior. Only applies when the handler does not set its own Cache-Control header. Unskip two E2E fixme cases and add vitest coverage. * fix: guard revalidate=0 and add proper test fixtures - Skip Cache-Control injection when revalidate is 0 (means "never cache") - Add /api/custom-cache fixture that sets its own Cache-Control header - Add /api/no-cache fixture with revalidate=0 - Fix "does not override" test to use a fixture that actually sets Cache-Control - Add revalidate=0 test case |
||
|
|
287923ebee | chore: add out-e2e to .gitignore (#304) | ||
|
|
d3b80ca247 |
feat: add Nix flake for reproducible dev environment (#238)
* feat: add Nix flake for reproducible dev environment - flake.nix with devShell (Node.js 24, pnpm, oxlint, Playwright, gh) - nix/checks.nix for hermetic lint/typecheck/test via nix flake check - shell.nix for backward compat, .envrc for direnv integration * fix: use corepack for exact pnpm version pinning - corepack reads packageManager field from package.json - --install-directory to writable .corepack/bin (Nix store is read-only) - COREPACK_ENABLE_DOWNLOAD_PROMPT=0 for non-interactive downloads - Remove checks.nix (sandboxed pnpm install infeasible) - Fix stale check to use .modules.yaml - Remove Playwright from Nix (let pnpm manage) - Pin shell.nix to flake-compat rev from flake.lock * chore: address review feedback on Nix dev shell - Remove unused lib and stdenv function arguments - Replace no-op PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD env var with comments documenting why we don't use Nix-provided browsers and the NixOS system library limitation - Make pnpm install non-fatal in shellHook so the shell still opens cleanly if the lockfile is stale - Improve staleness check readability (use -f guard instead of 2>/dev/null redirect) --------- Co-authored-by: Steve Faulkner <sfaulkner@cloudflare.com> |
||
|
|
12fea722b6 | Initial public release of vinext |