@thomas.f/prnext 0.1.16-alpha → 0.1.18-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI.md +63 -0
- package/README.md +35 -503
- package/build/ADAPTERS.md +27 -2
- package/build/actions.mjs +6 -1
- package/build/analyze.mjs +340 -0
- package/build/app-config.mjs +20 -8
- package/build/app-static.mjs +41 -14
- package/build/app-styles.mjs +79 -0
- package/build/app.mjs +99 -31
- package/build/build-lock.mjs +6 -6
- package/build/bundle-runtime.mjs +39 -11
- package/build/cache-components.mjs +1 -1
- package/build/cache-handlers.mjs +1 -1
- package/build/check.mjs +56 -11
- package/build/compact-css.mjs +53 -0
- package/build/compilation-cache.mjs +269 -0
- package/build/compilation-store.mjs +142 -0
- package/build/compiler.mjs +51 -4
- package/build/concurrent.mjs +12 -0
- package/build/config.mjs +50 -13
- package/build/create.mjs +239 -0
- package/build/css-modules.mjs +65 -10
- package/build/deployment-assets.mjs +89 -0
- package/build/deployment-config.mjs +18 -0
- package/build/dev-compiler-health.mjs +11 -0
- package/build/dev-css-update.mjs +85 -0
- package/build/dev-dependencies.mjs +44 -0
- package/build/dev-discovery.mjs +28 -0
- package/build/dev-worker.mjs +14 -5
- package/build/dev.mjs +64 -6
- package/build/dynamic.mjs +1 -1
- package/build/edge.mjs +5 -4
- package/build/fonts.mjs +1 -1
- package/build/framework-imports.mjs +50 -0
- package/build/html-only-config.mjs +53 -0
- package/build/html-only-graph.mjs +67 -0
- package/build/incremental.mjs +8 -4
- package/build/index.mjs +140 -112
- package/build/inspect.mjs +3 -0
- package/build/inspection-summary.mjs +37 -4
- package/build/instrumentation.mjs +30 -0
- package/build/loader-cache.mjs +53 -26
- package/build/metadata-routes.mjs +3 -4
- package/build/migrate.mjs +60 -57
- package/build/migration-audit.mjs +1 -1
- package/build/native-type-config.mjs +37 -0
- package/build/npm-packages.mjs +3 -18
- package/build/package-manager.mjs +308 -0
- package/build/persistent-cache.mjs +112 -0
- package/build/precompress.mjs +62 -30
- package/build/prerender-cache.mjs +70 -0
- package/build/prerender-config.mjs +29 -0
- package/build/prerender-pages.mjs +100 -0
- package/build/prerender-pool.mjs +165 -0
- package/build/prerender-process-worker.mjs +58 -0
- package/build/prerender-worker.mjs +10 -0
- package/build/production-builder.mjs +129 -0
- package/build/react-compiler-report.mjs +225 -0
- package/build/react-compiler.mjs +139 -0
- package/build/runtime-contract.mjs +2 -2
- package/build/scan.mjs +4 -4
- package/build/source-analysis.mjs +42 -0
- package/build/static-adapter.mjs +13 -5
- package/build/static-export.mjs +4 -4
- package/build/static-input.mjs +48 -0
- package/build/styles.mjs +17 -3
- package/build/transform-cache.mjs +37 -4
- package/build/transform.mjs +1 -1
- package/build/type-command.mjs +41 -0
- package/build/typed-routes.mjs +95 -0
- package/build/typescript-dev-worker.mjs +18 -0
- package/build/typescript-dev.mjs +49 -0
- package/build/typescript-native-worker.mjs +55 -0
- package/build/typescript-native.mjs +18 -0
- package/build/typescript-toolchain.mjs +19 -0
- package/build/typescript-watch.mjs +22 -0
- package/build/typescript.mjs +11 -8
- package/build/webpack-graph.mjs +170 -30
- package/build/worker-memory.mjs +9 -0
- package/build/worker-preload.mjs +9 -0
- package/cli.mjs +162 -122
- package/compat/activity-cache.cjs +26 -0
- package/compat/after.cjs +6 -4
- package/compat/app-layout-context.cjs +52 -2
- package/compat/base64.cjs +10 -0
- package/compat/cache-handlers.cjs +12 -2
- package/compat/cache-wire.cjs +28 -0
- package/compat/cache.cjs +2 -1
- package/compat/cache.d.cts +4 -0
- package/compat/cookies.cjs +21 -5
- package/compat/data-cache.cjs +12 -8
- package/compat/flight-delta.cjs +150 -0
- package/compat/headers.cjs +4 -2
- package/compat/incremental-cache.cjs +20 -7
- package/compat/index.d.ts +89 -10
- package/compat/link.cjs +12 -9
- package/compat/link.d.cts +4 -3
- package/compat/navigation-authorization.cjs +9 -0
- package/compat/navigation-stages.cjs +19 -0
- package/compat/navigation.d.cts +4 -3
- package/compat/offline-store.cjs +11 -0
- package/compat/offline.cjs +5 -0
- package/compat/offline.d.cts +2 -0
- package/compat/redis-cache.cjs +201 -0
- package/compat/redis-cache.d.cts +37 -0
- package/compat/router.d.cts +4 -3
- package/compat/server-primitives.cjs +31 -11
- package/compat/server.d.cts +15 -2
- package/compat/static-generation.cjs +7 -0
- package/compat/typed-route.d.cts +17 -0
- package/compat/use-cache.cjs +3 -0
- package/docs/ai/compatibility.md +275 -0
- package/docs/ai/data.md +288 -0
- package/docs/ai/deployment.md +269 -0
- package/docs/ai/manifest.json +11 -0
- package/docs/ai/quickstart.md +171 -0
- package/docs/ai/routing.md +214 -0
- package/docs/ai/troubleshooting.md +155 -0
- package/index.mjs +2 -0
- package/native/diagnostics.mjs +34 -0
- package/native/resolve.mjs +7 -2
- package/package.json +44 -7
- package/release/ai-docs.mjs +48 -0
- package/release/verify.mjs +2 -0
- package/runtime/action-client.mjs +10 -4
- package/runtime/action-server.mjs +2 -0
- package/runtime/ai-docs.mjs +202 -0
- package/runtime/app-client.mjs +226 -68
- package/runtime/app-content.mjs +4 -3
- package/runtime/app-partial-client.mjs +3 -0
- package/runtime/app-partial.mjs +1 -1
- package/runtime/app-prefetch-constants.mjs +4 -0
- package/runtime/app-prefetch.mjs +2 -3
- package/runtime/app-render-key.mjs +5 -0
- package/runtime/app-render.mjs +100 -28
- package/runtime/app-routing.mjs +22 -9
- package/runtime/app-static.mjs +18 -8
- package/runtime/app-stream-html.mjs +10 -53
- package/runtime/app-style-selection.mjs +34 -0
- package/runtime/app-styles.mjs +154 -0
- package/runtime/cache-components-rsc.mjs +4 -1
- package/runtime/cache-request.mjs +2 -1
- package/runtime/cloud/archive.mjs +5 -6
- package/runtime/compile-cache.mjs +8 -0
- package/runtime/deployment-client.mjs +19 -0
- package/runtime/dev-ai-brands.mjs +26 -0
- package/runtime/dev-ai-style.mjs +99 -0
- package/runtime/dev-build-reasons.mjs +25 -0
- package/runtime/dev-cache-control.mjs +53 -0
- package/runtime/dev-client.mjs +245 -46
- package/runtime/dev-compiler-broker.mjs +42 -0
- package/runtime/dev-console-copy.mjs +19 -0
- package/runtime/dev-console.mjs +106 -0
- package/runtime/dev-dependency-graph.mjs +40 -0
- package/runtime/dev-element-picker-style.mjs +27 -0
- package/runtime/dev-element-picker.mjs +213 -0
- package/runtime/dev-error-overlay-style.mjs +41 -0
- package/runtime/dev-error-overlay.mjs +167 -0
- package/runtime/dev-error-report.mjs +121 -0
- package/runtime/dev-file-changes.mjs +1 -1
- package/runtime/dev-gateway.mjs +44 -0
- package/runtime/dev-host-relay.mjs +66 -0
- package/runtime/dev-indicator.mjs +191 -0
- package/runtime/dev-issue-motion.mjs +214 -0
- package/runtime/dev-lazy-tool.mjs +34 -0
- package/runtime/dev-logo.mjs +2 -0
- package/runtime/dev-notification.mjs +81 -0
- package/runtime/dev-popout.mjs +34 -0
- package/runtime/dev-position.mjs +107 -0
- package/runtime/dev-preview-touch.mjs +122 -0
- package/runtime/dev-runtime-pool.mjs +45 -0
- package/runtime/dev-runtime-spare.mjs +57 -0
- package/runtime/dev-tools-client.mjs +155 -0
- package/runtime/dev-tools-mcp.mjs +126 -0
- package/runtime/dev-tools-metrics.mjs +31 -0
- package/runtime/dev-tools-model.mjs +42 -0
- package/runtime/dev-tools-panel.mjs +341 -0
- package/runtime/dev-tools-result.mjs +37 -0
- package/runtime/dev-tools-server.mjs +256 -0
- package/runtime/dev-tools-source.mjs +104 -0
- package/runtime/dev-tooltip.mjs +94 -0
- package/runtime/dev-ui-icons.mjs +8 -0
- package/runtime/dev-workbench-style.mjs +106 -0
- package/runtime/dev-workbench.mjs +428 -0
- package/runtime/dev-worker-logs.mjs +31 -0
- package/runtime/development.mjs +324 -0
- package/runtime/document.mjs +1 -1
- package/runtime/edge.mjs +6 -5
- package/runtime/env.mjs +2 -1
- package/runtime/fetch-cache.mjs +10 -8
- package/runtime/flight-delta.mjs +50 -0
- package/runtime/flight-tap.mjs +28 -0
- package/runtime/html-only.mjs +27 -0
- package/runtime/http.mjs +2 -0
- package/runtime/incremental-cache.mjs +25 -4
- package/runtime/instrumentation.mjs +49 -0
- package/runtime/navigation-recovery.mjs +36 -0
- package/runtime/navigation.mjs +7 -0
- package/runtime/node-html-stream.mjs +47 -0
- package/runtime/pages-client.mjs +24 -8
- package/runtime/pages-navigation.mjs +54 -64
- package/runtime/persistent/client.mjs +6 -5
- package/runtime/persistent/daemon.mjs +66 -56
- package/runtime/persistent/native-proxy.mjs +63 -0
- package/runtime/prefetch-scheduler.mjs +110 -0
- package/runtime/preload.mjs +12 -0
- package/runtime/profile.mjs +14 -0
- package/runtime/profiles.json +2 -2
- package/runtime/render.mjs +3 -0
- package/runtime/route-pattern.mjs +44 -0
- package/runtime/rsc-worker.mjs +41 -12
- package/runtime/trace.mjs +78 -0
- package/runtime/typed-route.mjs +19 -0
- package/runtime/watch-project.mjs +29 -18
- package/runtime/worker.mjs +102 -24
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Compatibility and migration
|
|
2
|
+
|
|
3
|
+
[AI documentation index](../../AI.md)
|
|
4
|
+
|
|
5
|
+
## Treat compatibility as a checked contract
|
|
6
|
+
|
|
7
|
+
PRNext adapts many public Next.js conventions; it is not a drop-in implementation
|
|
8
|
+
of every Next.js version. Package installation, a recognized import or a green
|
|
9
|
+
source audit does not prove an application works. The installed package's
|
|
10
|
+
metadata, declarations, diagnostics and executable behavior are the authority
|
|
11
|
+
for this release. Do not use an old repository checklist to override them.
|
|
12
|
+
|
|
13
|
+
Common supported areas include App/Pages routing, React Server Components,
|
|
14
|
+
Server Actions, request APIs, navigation, route metadata, supported cache APIs,
|
|
15
|
+
CSS Modules and the project's PostCSS pipeline. Scope varies by runtime and
|
|
16
|
+
option. Advanced parallel/intercepting routing, custom webpack/loaders, package
|
|
17
|
+
transpilation, image/font tooling and caching deserve targeted build and browser
|
|
18
|
+
tests. Support for one configuration shape does not imply support for all
|
|
19
|
+
upstream plugin behavior.
|
|
20
|
+
|
|
21
|
+
## Instrumentation and tracing
|
|
22
|
+
|
|
23
|
+
Use a single `instrumentation.ts`, `.js`, `.mjs` or `.cjs` at the project root
|
|
24
|
+
or in `src`. Export an optional async `register()` for runtime initialization
|
|
25
|
+
and an optional async `onRequestError(error, request, context)` for reporting.
|
|
26
|
+
The `Instrumentation.onRequestError` type is exported from PRNext's root API.
|
|
27
|
+
`process.env.NEXT_RUNTIME` distinguishes `nodejs` and `edge`; conditional imports
|
|
28
|
+
keep Node SDKs out of an Edge bundle. Registration runs once per server realm,
|
|
29
|
+
including the separate RSC realm, before application requests. A production
|
|
30
|
+
prerender does not run the runtime startup hook. Request-time ISR and PPR
|
|
31
|
+
regeneration initialize their server realm and report failures through the same
|
|
32
|
+
hooks. Repeated propagation of an RSC error to the HTML worker does not report
|
|
33
|
+
the same error again.
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import type { Instrumentation } from '@thomas.f/prnext'
|
|
37
|
+
|
|
38
|
+
export async function register() {
|
|
39
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
40
|
+
await import('./observability.node')
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const onRequestError: Instrumentation.onRequestError = async (
|
|
45
|
+
error, request, context
|
|
46
|
+
) => {
|
|
47
|
+
await reportError(error, request, context)
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`reportError` above is an application function, not a PRNext API. Initialization
|
|
52
|
+
has a 30-second budget. Each error hook has a five-second budget; reporting
|
|
53
|
+
failure does not replace the application failure. Redirect/not-found control
|
|
54
|
+
signals are excluded. Hooks receive request information: the application owns
|
|
55
|
+
redaction before sending that information to a third party.
|
|
56
|
+
|
|
57
|
+
For built-in correlated traces, explicitly set
|
|
58
|
+
`OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` to an OTLP HTTP collector's complete traces
|
|
59
|
+
URL and `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/json`. Alternatively,
|
|
60
|
+
`OTEL_EXPORTER_OTLP_ENDPOINT` supplies a base URL with `/v1/traces` appended.
|
|
61
|
+
`OTEL_SERVICE_NAME`, `OTEL_EXPORTER_OTLP_TRACES_HEADERS` (or general
|
|
62
|
+
`OTEL_EXPORTER_OTLP_HEADERS`) and `OTEL_SDK_DISABLED=true` are supported. Keep
|
|
63
|
+
exporter credentials in the server environment. This built-in path supports
|
|
64
|
+
HTTP JSON, not gRPC or HTTP protobuf; use your own SDK for other protocols.
|
|
65
|
+
|
|
66
|
+
Native HTTP spans cover static and dynamic responses through body completion
|
|
67
|
+
or cancellation. Node, RSC and fetch spans share W3C trace context. Export queues
|
|
68
|
+
are bounded and telemetry is best effort; an unavailable collector does not
|
|
69
|
+
block a site response. Built-in span attributes exclude bodies, cookie values,
|
|
70
|
+
query strings and authorization headers. An application-installed
|
|
71
|
+
`@opentelemetry/api` can use the same parent context when its SDK installs a
|
|
72
|
+
context manager in `register`. No SDK is installed automatically, and this does
|
|
73
|
+
not certify every vendor integration.
|
|
74
|
+
|
|
75
|
+
## Production bytes and navigation
|
|
76
|
+
|
|
77
|
+
Production CSS Modules use deterministic compact class and animation names.
|
|
78
|
+
Global classes and declared composition exports retain their meaning; development
|
|
79
|
+
keeps readable names. Internal JavaScript exports are shortened by the selected
|
|
80
|
+
compiler, while public exports and dynamic imports keep their interfaces. Asset
|
|
81
|
+
hashes and source maps remain compiler-owned.
|
|
82
|
+
|
|
83
|
+
App navigation can negotiate binary differential Flight responses. Every request
|
|
84
|
+
still runs fresh rendering and access checks. The server retains at most 64
|
|
85
|
+
completed bases, 32 MiB in total, with a two-MiB per-base limit and 30-second
|
|
86
|
+
expiry. Bases are keyed by deployment and credentials; an unknown, expired or
|
|
87
|
+
incompatible base produces ordinary Flight. The browser retains one completed
|
|
88
|
+
base, streams reconstructed bytes to React and can retry one failed differential
|
|
89
|
+
navigation as a full GET. Server Actions are never replayed through this path.
|
|
90
|
+
Per worker, at most eight captures and two encoders run together. Additional
|
|
91
|
+
requests use ordinary Flight, keeping transient transport work bounded too.
|
|
92
|
+
|
|
93
|
+
Configuration uses one `next.config.*` or `prnext.config.*` file and rejects
|
|
94
|
+
unknown keys rather than ignoring them. React Compiler is available through an
|
|
95
|
+
explicit `reactCompiler` option described below. `typedRoutes: true` is
|
|
96
|
+
implemented through PRNext's generated route registry. Do not copy a full
|
|
97
|
+
Next.js configuration template into a new application.
|
|
98
|
+
|
|
99
|
+
The repository's reference tests build and run matching applications against
|
|
100
|
+
Next.js 16.4.3, including mounted App navigation, form Actions and cookies,
|
|
101
|
+
metadata, Pages locale routing, redirects, APIs and selected webpack loader
|
|
102
|
+
contracts. These executable examples cover specific behavior; they do not
|
|
103
|
+
certify every Next.js application or plugin. `NextRequest.nextUrl` understands
|
|
104
|
+
data-route build IDs and locales, and request-cookie mutations synchronize the
|
|
105
|
+
request header. Request cookies have different mutation results from response
|
|
106
|
+
cookies; do not use them interchangeably.
|
|
107
|
+
|
|
108
|
+
A locked real-application fixture additionally exercises Better Auth 1.7.14
|
|
109
|
+
(email/password, session cookies and logout), Drizzle ORM 0.45.4 over SQLite
|
|
110
|
+
through its proxy driver, next-intl 4.14.9 (server and client translations),
|
|
111
|
+
and the MDX 3.1.1 webpack loader against Next.js 16.4.3. It covers authenticated
|
|
112
|
+
Server Actions, user-owned rows, cookie/locale isolation, client navigation and
|
|
113
|
+
Server Component `after()` callbacks. This is evidence for those workflows,
|
|
114
|
+
not a guarantee for every plugin, provider or deployment configuration.
|
|
115
|
+
|
|
116
|
+
PRNext-specific options such as `prerender` and `htmlOnly` are described in
|
|
117
|
+
[Build and deployment](deployment.md). Do not pass them to an upstream Next.js
|
|
118
|
+
build when comparing the two implementations.
|
|
119
|
+
|
|
120
|
+
## TypeScript 7 and earlier compilers
|
|
121
|
+
|
|
122
|
+
PRNext uses the application's installed TypeScript. TypeScript 7 runs through its
|
|
123
|
+
official native `tsc` command for production checks, `prnext typecheck` and live
|
|
124
|
+
development diagnostics. Install TypeScript normally, including its platform
|
|
125
|
+
optional dependencies. PRNext does not download a compiler during a build.
|
|
126
|
+
TypeScript 5 and 6 retain their compiler API integration.
|
|
127
|
+
|
|
128
|
+
Checks use `--noEmit` and keep incremental compiler state in an owned temporary
|
|
129
|
+
directory. Development reports updated errors and clears fixed diagnostics;
|
|
130
|
+
new source files and configuration changes restart the native watch generation.
|
|
131
|
+
`typedRoutes` also supports native TypeScript and preserves JSONC comments when
|
|
132
|
+
adding its generated declaration to the config. Compiler support does not imply
|
|
133
|
+
that every application is ready for TypeScript 7's own language/config changes.
|
|
134
|
+
|
|
135
|
+
## React Compiler
|
|
136
|
+
|
|
137
|
+
Enable the bundled official React Compiler in the project's existing config:
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
export default {
|
|
141
|
+
reactCompiler: true,
|
|
142
|
+
};
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
No separate compiler installation is required. The default is disabled;
|
|
146
|
+
`reactCompiler: false` preserves the uncompiled component path. Enabled builds
|
|
147
|
+
optimize project-owned browser components in both Pages and App applications,
|
|
148
|
+
in development and production. App Client Components also use the transform in
|
|
149
|
+
their isolated server-rendering graph. The Pages server graph stays uncompiled,
|
|
150
|
+
including APIs, custom Document code and data-loader utilities, so ordinary
|
|
151
|
+
server functions never acquire client-only memoization hooks. React Server
|
|
152
|
+
Components, Server Action modules, PRNext internals, generated entrypoints and
|
|
153
|
+
npm packages are not compiled. Keep the matching React 19 peer versions required
|
|
154
|
+
by the installed framework.
|
|
155
|
+
|
|
156
|
+
Ordinary `.mts`/`.cts` hook helpers can be optimized; server/client directives
|
|
157
|
+
in those extensions remain unsupported. Decorated `.mts`/`.cts` utility modules
|
|
158
|
+
keep their native compilation path while importing React components can still
|
|
159
|
+
be optimized.
|
|
160
|
+
|
|
161
|
+
For gradual adoption, use `reactCompiler: { compilationMode: 'annotation' }`, then
|
|
162
|
+
put `"use memo";` at the beginning of each component or hook to optimize. In
|
|
163
|
+
either mode, `"use no memo";` excludes an individual function. Supported object
|
|
164
|
+
options are `compilationMode: 'infer' | 'annotation'`,
|
|
165
|
+
`panicThreshold: 'none' | 'critical_errors' | 'all_errors'` and `target: '19'`.
|
|
166
|
+
Defaults are `'infer'`, `'none'` and `'19'`; other fields are rejected.
|
|
167
|
+
|
|
168
|
+
After a successful build, inspect the compiler's actual results:
|
|
169
|
+
|
|
170
|
+
```sh
|
|
171
|
+
prnext compiler
|
|
172
|
+
prnext compiler --json
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The report names observed functions, their project-relative files, optimization
|
|
176
|
+
or skip status, and the compiler's reasons. These are transform decisions;
|
|
177
|
+
server-code removal and tree shaking can later omit a function from the browser
|
|
178
|
+
bundle. Cached transforms retain their
|
|
179
|
+
diagnostics and are identified as reused. Browser and server graphs do not
|
|
180
|
+
inflate the function count. An incremental build can reuse graph inputs without
|
|
181
|
+
observing every transform; the report states that scope rather than claiming
|
|
182
|
+
complete application coverage. Disabled compilation is reported explicitly.
|
|
183
|
+
The report describes the last successful build, stays outside public assets and
|
|
184
|
+
does not include source code. A failed build preserves the previous report.
|
|
185
|
+
|
|
186
|
+
The compiler can skip code that cannot be safely optimized. Follow the Rules of
|
|
187
|
+
React and check actual behavior rather than assuming every component was
|
|
188
|
+
compiled. It reduces repeated component work; it does not guarantee faster
|
|
189
|
+
server responses, smaller JavaScript or a specific speed multiplier. Validate
|
|
190
|
+
hydration, interactions and Fast Refresh in the application, then compare a
|
|
191
|
+
production build with the option enabled and disabled. Compilation adds build
|
|
192
|
+
work; PRNext caches pure transforms with their compiler version and settings.
|
|
193
|
+
|
|
194
|
+
See the [official React Compiler documentation](https://react.dev/learn/react-compiler).
|
|
195
|
+
|
|
196
|
+
Only explicit private Next.js import adapters are supported. Do not add arbitrary
|
|
197
|
+
`next/dist/...` imports or install another Next runtime to satisfy one: isolate
|
|
198
|
+
or replace the incompatible dependency, retain the original framework where
|
|
199
|
+
needed, and describe the limitation honestly.
|
|
200
|
+
|
|
201
|
+
## Migrate conservatively
|
|
202
|
+
|
|
203
|
+
Use the project's existing package manager. For npm, install the intended
|
|
204
|
+
published PRNext release and its matching React peers, then inspect the dry run:
|
|
205
|
+
|
|
206
|
+
```sh
|
|
207
|
+
npm i --save-exact @thomas.f/prnext react@19.3.1 react-dom@19.3.1 react-server-dom-webpack@19.3.1
|
|
208
|
+
npx --no-install prnext migrate --dry-run
|
|
209
|
+
npx --no-install prnext migrate --check --json
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Review scripts, manager/workspace detection, configuration and reported source
|
|
213
|
+
conflicts. When the plan is correct:
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
npx --no-install prnext migrate
|
|
217
|
+
npx --no-install prnext check --json
|
|
218
|
+
npx --no-install prnext typecheck
|
|
219
|
+
npx --no-install prnext build
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Migration changes selected scripts/dependencies, backs up package files and
|
|
223
|
+
existing lockfiles, and keeps Next.js and application source. Public `next/*`
|
|
224
|
+
imports can remain. Do not remove Next, replace all imports or recreate the
|
|
225
|
+
application without a separate need.
|
|
226
|
+
|
|
227
|
+
Installation honors npm, pnpm and Yarn Classic/Berry and the owning workspace
|
|
228
|
+
root. Conflicting managers, unsafe filesystem entries and unlisted workspaces
|
|
229
|
+
can block automatic install. `migrate --no-install` prepares the manifest for
|
|
230
|
+
manual manager execution. Custom shell scripts may require a manual edit.
|
|
231
|
+
An installation failure attempts safe manifest/lockfile restoration; it cannot
|
|
232
|
+
roll back every dependency directory or manager cache. Never solve peer conflicts
|
|
233
|
+
by silently adding `--force` or `--legacy-peer-deps`.
|
|
234
|
+
|
|
235
|
+
`migrate --check` audits without applying a migration. Configuration evaluation
|
|
236
|
+
can run project code, and installed custom loaders still require a real build.
|
|
237
|
+
The audit is not a sandbox for untrusted projects.
|
|
238
|
+
|
|
239
|
+
## Compare running applications
|
|
240
|
+
|
|
241
|
+
Start the original application and the candidate on separate available ports.
|
|
242
|
+
Create `paths.json` with representative concrete URLs:
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
["/", "/products/demo", "/api/health"]
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Then compare public GET responses:
|
|
249
|
+
|
|
250
|
+
```sh
|
|
251
|
+
prnext migrate --check --against http://localhost:3000 --candidate http://localhost:3001 --routes paths.json
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
The comparison does not authenticate or follow redirects. It compares response
|
|
255
|
+
samples, including status, content type and selected body semantics; it does not
|
|
256
|
+
prove hydration, styling, actions or all dynamic routes. Visit important routes
|
|
257
|
+
in a real browser, test authorized and unauthorized states, and run the existing
|
|
258
|
+
application tests. Keep the original setup available until the candidate is
|
|
259
|
+
actually verified. Timings from this comparison are not controlled benchmarks.
|
|
260
|
+
|
|
261
|
+
## Boundaries that often matter
|
|
262
|
+
|
|
263
|
+
React server/client directives in `.mts`/`.cts` are rejected; use `.ts`/`.tsx`.
|
|
264
|
+
App Route Handlers use Web Request/Response, while Pages APIs retain their own
|
|
265
|
+
request/response contract. App and Pages router hooks are not interchangeable.
|
|
266
|
+
Edge code cannot assume Node APIs or Node-only package behavior.
|
|
267
|
+
|
|
268
|
+
HTTP/1 WebSockets can tunnel through supported external HTTP(S) rewrites and
|
|
269
|
+
hosting gateways; App/Pages handlers do not gain a WebSocket server API. Static
|
|
270
|
+
imports accept completed public browser output, not another framework's SSR
|
|
271
|
+
server. See [Deployment](deployment.md) before choosing an adapter.
|
|
272
|
+
|
|
273
|
+
When a feature is missing, give its exact failing API/option and a supported
|
|
274
|
+
alternative. Do not claim full compatibility, invent a replacement method or
|
|
275
|
+
mask the error with an empty shim.
|
package/docs/ai/data.md
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# Request data, actions and caching
|
|
2
|
+
|
|
3
|
+
[AI documentation index](../../AI.md)
|
|
4
|
+
|
|
5
|
+
## Request context
|
|
6
|
+
|
|
7
|
+
Use server request APIs only while handling a PRNext request. Await `headers()`
|
|
8
|
+
and `cookies()` from `next/headers`. Headers are read-only; cookie writes belong
|
|
9
|
+
in a Server Action or Route Handler before response headers commit. Do not read
|
|
10
|
+
the current request at module initialization or stash request data in a
|
|
11
|
+
process-global variable.
|
|
12
|
+
|
|
13
|
+
The following complete example stores a non-sensitive display preference. It is
|
|
14
|
+
not an authentication or session implementation.
|
|
15
|
+
|
|
16
|
+
### `app/preferences/actions.ts`
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
'use server';
|
|
20
|
+
|
|
21
|
+
import { cookies } from 'next/headers';
|
|
22
|
+
import { revalidatePath } from 'next/cache';
|
|
23
|
+
|
|
24
|
+
export async function saveTheme(form: FormData) {
|
|
25
|
+
const theme = form.get('theme');
|
|
26
|
+
if (theme !== 'light' && theme !== 'dark') throw new Error('Invalid theme');
|
|
27
|
+
const store = await cookies();
|
|
28
|
+
store.set('theme', theme, { httpOnly: true, sameSite: 'lax', path: '/' });
|
|
29
|
+
revalidatePath('/preferences');
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### `app/preferences/page.tsx`
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { cookies } from 'next/headers';
|
|
37
|
+
import { saveTheme } from './actions';
|
|
38
|
+
|
|
39
|
+
export default async function Preferences() {
|
|
40
|
+
const store = await cookies();
|
|
41
|
+
const theme = store.get('theme')?.value === 'dark' ? 'dark' : 'light';
|
|
42
|
+
return <main>
|
|
43
|
+
<h1>Preferences</h1>
|
|
44
|
+
<p>Current theme: {theme}</p>
|
|
45
|
+
<form action={saveTheme}>
|
|
46
|
+
<select name="theme" defaultValue={theme} aria-label="Theme">
|
|
47
|
+
<option value="light">Light</option>
|
|
48
|
+
<option value="dark">Dark</option>
|
|
49
|
+
</select>
|
|
50
|
+
<button type="submit">Save</button>
|
|
51
|
+
</form>
|
|
52
|
+
</main>;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Server Actions accept untrusted input even when invoked through a form you
|
|
57
|
+
rendered. Check authentication, authorization and input on every protected
|
|
58
|
+
mutation. For real session cookies, use the application's session library and
|
|
59
|
+
production HTTPS policy, including appropriate secure cookie settings.
|
|
60
|
+
|
|
61
|
+
## Fetch deliberately
|
|
62
|
+
|
|
63
|
+
Choose freshness explicitly. Request-specific or sensitive reads normally need
|
|
64
|
+
`fetch(url, { cache: 'no-store' })`. Shared public data can opt into
|
|
65
|
+
`cache: 'force-cache'` and `next: { revalidate: seconds, tags: [...] }`. The
|
|
66
|
+
`next` extension belongs to PRNext's server fetch integration, not browser fetch.
|
|
67
|
+
Check `response.ok` and validate the returned data before using it.
|
|
68
|
+
|
|
69
|
+
Under the default route configuration, an ordinary fetch or `next.tags` alone
|
|
70
|
+
does not request persistent caching. Route configuration can change defaults;
|
|
71
|
+
inspect it before diagnosing a cache. Avoid conflicting `cache` and `revalidate`
|
|
72
|
+
options. A successful fetch cache hit is different from cached HTML, a browser
|
|
73
|
+
router cache hit or a compiler cache hit.
|
|
74
|
+
|
|
75
|
+
`unstable_cache` caches JSON-serializable function results. A runnable public-data
|
|
76
|
+
example:
|
|
77
|
+
|
|
78
|
+
### `lib/catalog.ts`
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { unstable_cache } from 'next/cache';
|
|
82
|
+
|
|
83
|
+
export const readCatalog = unstable_cache(
|
|
84
|
+
async () => [{ id: 'demo', name: 'Demo product' }],
|
|
85
|
+
['public-catalog-v1'],
|
|
86
|
+
{ tags: ['catalog'], revalidate: 60 },
|
|
87
|
+
);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The static array stands in for a real server-side data read. Do not perform
|
|
91
|
+
mutations in the cached callback. Read cookies/headers outside `unstable_cache`
|
|
92
|
+
and pass required values as arguments. Include tenant/user identity in any
|
|
93
|
+
appropriate cache key and authorize before access; never treat a shared cache as
|
|
94
|
+
a session store. Avoid caching private data unless its isolation is deliberate
|
|
95
|
+
and tested. Changes in closed-over values need explicit key parts or arguments.
|
|
96
|
+
|
|
97
|
+
## Invalidate in the mutation
|
|
98
|
+
|
|
99
|
+
`revalidatePath('/preferences')` invalidates a concrete path. A dynamic pattern
|
|
100
|
+
requires its kind, such as `revalidatePath('/products/[slug]', 'page')`.
|
|
101
|
+
`revalidateTag('catalog', 'max')` marks tagged data stale for revalidation;
|
|
102
|
+
`updateTag('catalog')` expires it for read-your-own-writes in a Server Action.
|
|
103
|
+
`updateTag` is action-only; path/tag revalidation also supports Route Handlers.
|
|
104
|
+
Perform the underlying successful write before invalidating its cache.
|
|
105
|
+
|
|
106
|
+
Invalidation APIs are rejected during rendering, inside a cached callback and
|
|
107
|
+
after response headers have been sent. They do not delete unrelated build caches
|
|
108
|
+
or restart the server. Custom cache handlers can delegate these semantics; do
|
|
109
|
+
not infer their hit rate from PRNext's native-cache diagnostics.
|
|
110
|
+
|
|
111
|
+
The installed implementation also has `cacheComponents`, `'use cache'`,
|
|
112
|
+
`cacheLife` and `cacheTag` support. These are additional cache contracts; do not
|
|
113
|
+
enable them to silence a request-context error or assume their complete upstream
|
|
114
|
+
behavior. Keep a working `unstable_cache` or fetch solution unless the project
|
|
115
|
+
needs a different model.
|
|
116
|
+
|
|
117
|
+
## Navigation stages
|
|
118
|
+
|
|
119
|
+
Enable `cacheComponents: true` and `partialPrefetching: true` to separate runtime
|
|
120
|
+
App Shell work from per-link prefetch work and actual navigation work:
|
|
121
|
+
|
|
122
|
+
```jsx
|
|
123
|
+
import { Suspense } from 'react';
|
|
124
|
+
import { navigation, prefetch } from 'next/cache';
|
|
125
|
+
|
|
126
|
+
async function Recommendations() {
|
|
127
|
+
await prefetch();
|
|
128
|
+
return <div>{await getCachedRecommendations()}</div>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function ExpensiveReport() {
|
|
132
|
+
await navigation();
|
|
133
|
+
return <div>{await getCachedReport()}</div>;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export default function Page() {
|
|
137
|
+
return <>
|
|
138
|
+
<Suspense fallback={<p>Loading recommendations</p>}><Recommendations /></Suspense>
|
|
139
|
+
<Suspense fallback={<p>Loading report</p>}><ExpensiveReport /></Suspense>
|
|
140
|
+
</>;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Define and authorize the application-specific data functions above. Call gates
|
|
145
|
+
before invoking a cached function, never inside its cached scope. Both gates
|
|
146
|
+
require Cache Components. Static prerenders continue through them, so static
|
|
147
|
+
output can already contain the result. Without partial prefetching, `prefetch()`
|
|
148
|
+
has no effect and an explicit `Link prefetch={true}` requests the full route.
|
|
149
|
+
|
|
150
|
+
A default Link requests the shell. `prefetch={true}` permits per-link work;
|
|
151
|
+
content below `navigation()` waits for the navigation. Runtime previews are
|
|
152
|
+
private, size-bounded and tied to the request's authorization identity. They do
|
|
153
|
+
not authorize a subsequent navigation.
|
|
154
|
+
Uncached runtime fetches and `connection()` remain deferred during speculative
|
|
155
|
+
rendering. Put reusable I/O in a cached function to make it eligible for an
|
|
156
|
+
earlier stage; a gate does not itself cache data.
|
|
157
|
+
|
|
158
|
+
Pages and layouts may export `ensureStatic = 'shell'`, `'prefetch'` or
|
|
159
|
+
`'navigation'`. Earlier stages are included in stricter levels. A descendant
|
|
160
|
+
cannot weaken a parent; `false` conflicts with a static requirement elsewhere
|
|
161
|
+
in the route. `'auto'` adds no requirement. Client Component exports are rejected.
|
|
162
|
+
`'shell'` and `'prefetch'` request static output for those stages without adding
|
|
163
|
+
a separate full-route build check. `'navigation'` validates complete static
|
|
164
|
+
server output during build and development, including request APIs beneath
|
|
165
|
+
Suspense, metadata and complete dynamic parameter sets. It requires nonempty,
|
|
166
|
+
complete `generateStaticParams()` results for dynamic routes. All levels require
|
|
167
|
+
Cache Components; shell/prefetch levels need partial prefetching to select stages.
|
|
168
|
+
|
|
169
|
+
## Shared Redis Cache Components
|
|
170
|
+
|
|
171
|
+
The optional first-party Redis handler shares `'use cache'` results across Node
|
|
172
|
+
processes. Install `@redis/client@^6.3.0` only in applications using it; a normal PRNext
|
|
173
|
+
installation and generated project do not require Redis.
|
|
174
|
+
|
|
175
|
+
### `redis-handler.mjs`
|
|
176
|
+
|
|
177
|
+
```js
|
|
178
|
+
import { createRedisCache } from '@thomas.f/prnext/cache/redis';
|
|
179
|
+
|
|
180
|
+
export default createRedisCache({
|
|
181
|
+
namespace: 'my-app-production-v1',
|
|
182
|
+
urlEnv: 'REDIS_URL',
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### `prnext.config.mjs`
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
export default {
|
|
190
|
+
cacheComponents: true,
|
|
191
|
+
cacheHandlers: { remote: './redis-handler.mjs' },
|
|
192
|
+
};
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### `app/catalog/read.ts`
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import { cacheLife, cacheTag } from 'next/cache';
|
|
199
|
+
|
|
200
|
+
export async function readCatalog() {
|
|
201
|
+
'use cache: remote';
|
|
202
|
+
cacheLife('hours');
|
|
203
|
+
cacheTag('catalog');
|
|
204
|
+
return [{ id: 'demo', name: 'Demo product' }];
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Set the Redis URL in the server's runtime environment. It is not embedded in the
|
|
209
|
+
handler bundle. Replicas sharing results need the same namespace and compatible
|
|
210
|
+
build output. Use separate namespaces for unrelated apps, environments and
|
|
211
|
+
incompatible deployments. This factory handles Cache Components. The separate
|
|
212
|
+
incremental factory below handles native HTML/ISR, fetch and `unstable_cache`.
|
|
213
|
+
|
|
214
|
+
Cache fills use a bounded cross-process lease. Atomic tag generations prevent a
|
|
215
|
+
fill invalidated while running, or an expired lease owner, from publishing old
|
|
216
|
+
data. Soft tag invalidation retains stale-while-revalidate behavior; immediate
|
|
217
|
+
expiration prevents another replica from reading the old entry. Losing the tag
|
|
218
|
+
registry invalidates existing entries rather than resurrecting them.
|
|
219
|
+
|
|
220
|
+
Values are limited to 2 MiB, metadata to 64 KiB and each entry to 256 tags.
|
|
221
|
+
The tag registry is bounded; excess cardinality conservatively invalidates the
|
|
222
|
+
namespace. Default retention is at most seven days. Defaults use a 30-second
|
|
223
|
+
lease, a 2.5-second fill wait and one-second command timeout. Reads can fall back
|
|
224
|
+
to fresh computation on cache failure; invalidation failures remain errors.
|
|
225
|
+
Cached callbacks must be safe to execute more than once after timeout or outage:
|
|
226
|
+
leases reduce duplicate work, not provide exactly-once business operations.
|
|
227
|
+
|
|
228
|
+
An already connected node-redis client can be supplied as `client`; its lifecycle
|
|
229
|
+
remains the application's responsibility. Otherwise the handler connects lazily
|
|
230
|
+
and owns its client. Use Redis appropriate for the application's availability,
|
|
231
|
+
access controls and data sensitivity; a shared cache is not an authorization
|
|
232
|
+
boundary or a durable database.
|
|
233
|
+
|
|
234
|
+
## Shared Redis pages and request data
|
|
235
|
+
|
|
236
|
+
Configure `cacheHandler` with the constructor returned by the incremental factory:
|
|
237
|
+
|
|
238
|
+
```js
|
|
239
|
+
// incremental-redis.mjs
|
|
240
|
+
import { createRedisIncrementalCache } from '@thomas.f/prnext/cache/redis';
|
|
241
|
+
export default createRedisIncrementalCache({ namespace: 'my-app-production' });
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
```js
|
|
245
|
+
// prnext.config.mjs
|
|
246
|
+
export default {
|
|
247
|
+
cacheHandler: './incremental-redis.mjs',
|
|
248
|
+
cacheMaxMemorySize: 0,
|
|
249
|
+
};
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Set `REDIS_URL` at runtime and install the optional `@redis/client@^6.3.0` client.
|
|
253
|
+
The same configuration works for App and Pages HTML/ISR, static Route Handlers,
|
|
254
|
+
cacheable `fetch` and `unstable_cache`. It does not cache private dynamic pages.
|
|
255
|
+
Replicas must use compatible builds and share an application-specific namespace.
|
|
256
|
+
Cache Components still select their own `cacheHandlers`; both factories may use
|
|
257
|
+
the same namespace to share tag invalidations.
|
|
258
|
+
|
|
259
|
+
The runtime acquires a shared generation lease before rendering, checks for a
|
|
260
|
+
winner's result after waiting and carries that lease through publication. An
|
|
261
|
+
invalidation or expired lease rejects late writes atomically. Runtime reads and
|
|
262
|
+
publication remain bounded; unavailable Redis can prevent a page regeneration
|
|
263
|
+
from succeeding. A shared cache is not a durable database or an exactly-once
|
|
264
|
+
execution mechanism. Keep producers safe to retry.
|
|
265
|
+
|
|
266
|
+
Incremental entries preserve Buffer and Map values, have a 16 MiB serialized
|
|
267
|
+
limit and use V8-major-specific keys. The default generation lease is 60 seconds;
|
|
268
|
+
`leaseMs` can be configured up to 120 seconds. Configure it for the expected
|
|
269
|
+
generation duration. The default maximum storage age remains seven days.
|
|
270
|
+
New cacheHandler builds include a native generation-lease capability check;
|
|
271
|
+
use the matching PRNext native binary and rebuild existing output.
|
|
272
|
+
|
|
273
|
+
## Background work and durable data
|
|
274
|
+
|
|
275
|
+
`after()` from `next/server` is supported in Node Server Components (including
|
|
276
|
+
layouts and metadata), Route Handlers and Server Actions. It runs tracked
|
|
277
|
+
callbacks after the response completes or disconnects; static renders execute
|
|
278
|
+
them during the build. Edge lifecycles remain unsupported. In a Server Component,
|
|
279
|
+
read request data before registering the callback and capture the needed values:
|
|
280
|
+
`headers()`, `cookies()` and `draftMode()` inside that callback are rejected.
|
|
281
|
+
Route Handler and Action callbacks can read their retained request context.
|
|
282
|
+
Cookie writes and path/tag invalidation are rejected after the response;
|
|
283
|
+
invalidate before returning from the mutation.
|
|
284
|
+
|
|
285
|
+
Tracked callbacks are bounded by the route's `maxDuration` and shutdown
|
|
286
|
+
deadlines; forced termination can interrupt them. Use an external durable queue
|
|
287
|
+
for work that must survive a restart. Module globals, local runtime caches and
|
|
288
|
+
temporary files are not substitutes for a database or durable job store.
|