vinext 1.1.0 → 1.2.0
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/README.md +21 -9
- package/dist/build/client-build-config.d.ts +10 -0
- package/dist/build/client-build-config.js +18 -2
- package/dist/build/pages-client-assets-module.d.ts +8 -0
- package/dist/build/pages-client-assets-module.js +21 -1
- package/dist/build/prerender-paths.js +5 -3
- package/dist/build/run-prerender.js +1 -1
- package/dist/build/ssr-manifest.d.ts +2 -0
- package/dist/build/ssr-manifest.js +6 -2
- package/dist/check.js +7 -6
- package/dist/cli.js +2 -1
- package/dist/client/client-redirect-matcher.d.ts +14 -0
- package/dist/client/client-redirect-matcher.js +37 -0
- package/dist/client/client-redirects.d.ts +27 -0
- package/dist/client/client-redirects.js +28 -0
- package/dist/client/client-rewrites.d.ts +2 -1
- package/dist/client/client-rewrites.js +1 -1
- package/dist/config/config-matchers.d.ts +26 -11
- package/dist/config/config-matchers.js +78 -81
- package/dist/config/destination-params.d.ts +47 -0
- package/dist/config/destination-params.js +116 -0
- package/dist/config/next-config.d.ts +7 -0
- package/dist/config/next-config.js +3 -0
- package/dist/entries/app-rsc-entry.d.ts +4 -0
- package/dist/entries/app-rsc-entry.js +20 -6
- package/dist/entries/pages-client-entry.js +3 -1
- package/dist/entries/pages-server-entry.js +13 -37
- package/dist/index.d.ts +3 -1
- package/dist/index.js +134 -43
- package/dist/init-cloudflare.d.ts +9 -0
- package/dist/init-cloudflare.js +107 -31
- package/dist/init-platform.d.ts +4 -0
- package/dist/init-platform.js +27 -2
- package/dist/init.d.ts +1 -0
- package/dist/init.js +67 -3
- package/dist/plugins/ast-scope.d.ts +7 -0
- package/dist/plugins/ast-scope.js +59 -3
- package/dist/plugins/cache-flight-codec.d.ts +1 -1
- package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
- package/dist/plugins/dynamic-preload-metadata.js +9 -8
- package/dist/plugins/ignore-dynamic-requests.d.ts +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +3 -4
- package/dist/plugins/middleware-server-only.d.ts +5 -4
- package/dist/plugins/middleware-server-only.js +8 -5
- package/dist/plugins/pages-node-externals.js +1 -1
- package/dist/plugins/rsc-scan-glob-imports.d.ts +19 -0
- package/dist/plugins/rsc-scan-glob-imports.js +50 -0
- package/dist/plugins/strip-server-exports.js +262 -98
- package/dist/plugins/transform-result.d.ts +9 -5
- package/dist/plugins/transitive-externals.js +1 -1
- package/dist/plugins/typeof-window.d.ts +2 -2
- package/dist/plugins/use-cache-callable.js +8 -2
- package/dist/plugins/worker-server-only-imports.d.ts +20 -0
- package/dist/plugins/worker-server-only-imports.js +31 -0
- package/dist/plugins/worker-use-server.d.ts +25 -0
- package/dist/plugins/worker-use-server.js +129 -0
- package/dist/server/api-handler.d.ts +1 -0
- package/dist/server/api-handler.js +2 -1
- package/dist/server/app-browser-action-result.d.ts +1 -1
- package/dist/server/app-browser-action-result.js +9 -2
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-browser-server-action-client.js +1 -1
- package/dist/server/app-middleware.d.ts +11 -0
- package/dist/server/app-middleware.js +17 -2
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-cache.js +1 -1
- package/dist/server/app-page-dispatch.d.ts +3 -1
- package/dist/server/app-page-dispatch.js +4 -3
- package/dist/server/app-page-ppr-runtime.js +1 -1
- package/dist/server/app-page-render-observation.js +1 -1
- package/dist/server/app-page-request.js +53 -15
- package/dist/server/app-page-route-wiring.js +2 -2
- package/dist/server/app-pages-bridge.d.ts +1 -1
- package/dist/server/app-pages-bridge.js +2 -3
- package/dist/server/app-prerender-endpoints.js +9 -6
- package/dist/server/app-request-stage-dispatch.js +6 -2
- package/dist/server/app-request-stage-independent-entry.js +25 -5
- package/dist/server/app-response-stage-entry.js +10 -2
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +1 -0
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +5 -2
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-runtime.d.ts +4 -1
- package/dist/server/app-route-handler-runtime.js +45 -24
- package/dist/server/app-router-entry.js +24 -5
- package/dist/server/app-rsc-cache-busting.js +1 -1
- package/dist/server/app-rsc-errors.js +20 -16
- package/dist/server/app-rsc-handler.d.ts +7 -0
- package/dist/server/app-rsc-handler.js +85 -35
- package/dist/server/app-rsc-response-stage.js +4 -2
- package/dist/server/app-segment-config.d.ts +2 -1
- package/dist/server/app-server-action-execution.d.ts +2 -1
- package/dist/server/app-server-action-execution.js +61 -22
- package/dist/server/app-ssr-entry.js +2 -1
- package/dist/server/app-worker-stages.d.ts +5 -0
- package/dist/server/app-worker-stages.js +1 -1
- package/dist/server/cacheability-request.js +2 -2
- package/dist/server/client-build-files.d.ts +16 -0
- package/dist/server/client-build-files.js +36 -0
- package/dist/server/client-reuse-manifest.js +1 -1
- package/dist/server/dev-server.js +38 -27
- package/dist/server/dev-stack-sourcemap.js +18 -23
- package/dist/server/document-initial-head.d.ts +0 -11
- package/dist/server/document-initial-head.js +1 -1
- package/dist/server/forwarded-middleware-context.d.ts +5 -0
- package/dist/server/forwarded-middleware-context.js +22 -0
- package/dist/server/headers.d.ts +4 -1
- package/dist/server/headers.js +4 -1
- package/dist/server/http-conditional.d.ts +11 -0
- package/dist/server/http-conditional.js +10 -1
- package/dist/server/http-error-responses.d.ts +1 -1
- package/dist/server/image-optimization.d.ts +38 -0
- package/dist/server/image-optimization.js +93 -4
- package/dist/server/isr-cache.d.ts +10 -0
- package/dist/server/isr-cache.js +41 -6
- package/dist/server/metadata-route-response.js +9 -8
- package/dist/server/middleware-matcher.d.ts +2 -0
- package/dist/server/middleware-matcher.js +23 -2
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +33 -20
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +3 -1
- package/dist/server/multi-stage.d.ts +11 -0
- package/dist/server/normalize-path.d.ts +0 -13
- package/dist/server/normalize-path.js +1 -34
- package/dist/server/pages-api-route.d.ts +3 -2
- package/dist/server/pages-api-route.js +4 -3
- package/dist/server/pages-cache-tag.d.ts +12 -0
- package/dist/server/pages-cache-tag.js +19 -0
- package/dist/server/pages-client-assets.d.ts +2 -0
- package/dist/server/pages-data-route.d.ts +10 -0
- package/dist/server/pages-data-route.js +19 -2
- package/dist/server/pages-document-asset-props.d.ts +5 -1
- package/dist/server/pages-document-asset-props.js +13 -5
- package/dist/server/pages-document-splice.d.ts +19 -0
- package/dist/server/pages-document-splice.js +55 -0
- package/dist/server/pages-i18n.d.ts +12 -1
- package/dist/server/pages-i18n.js +18 -4
- package/dist/server/pages-node-compat.d.ts +16 -5
- package/dist/server/pages-node-compat.js +20 -12
- package/dist/server/pages-page-data.d.ts +32 -24
- package/dist/server/pages-page-data.js +50 -120
- package/dist/server/pages-page-handler.d.ts +0 -6
- package/dist/server/pages-page-handler.js +188 -126
- package/dist/server/pages-page-response.d.ts +12 -6
- package/dist/server/pages-page-response.js +41 -34
- package/dist/server/pages-request-pipeline.d.ts +10 -2
- package/dist/server/pages-request-pipeline.js +37 -18
- package/dist/server/pages-request-stage-entry.d.ts +6 -0
- package/dist/server/pages-request-stage-entry.js +71 -12
- package/dist/server/pages-response-stage-entry.js +4 -0
- package/dist/server/pages-revalidate.js +1 -1
- package/dist/server/pages-router-entry.js +4 -3
- package/dist/server/prerender-manifest.d.ts +3 -3
- package/dist/server/prerender-manifest.js +4 -3
- package/dist/server/prerender-work-unit-setup.js +4 -0
- package/dist/server/prod-server.d.ts +12 -0
- package/dist/server/prod-server.js +199 -69
- package/dist/server/proper-error.d.ts +4 -0
- package/dist/server/proper-error.js +31 -0
- package/dist/server/request-pipeline.d.ts +4 -1
- package/dist/server/request-pipeline.js +3 -2
- package/dist/server/revalidation-request.d.ts +1 -0
- package/dist/server/revalidation-request.js +1 -1
- package/dist/server/rsc-stream-hints.js +31 -2
- package/dist/server/seed-cache.d.ts +1 -0
- package/dist/server/seed-cache.js +5 -4
- package/dist/server/server-reference-loader.d.ts +4 -0
- package/dist/server/server-reference-loader.js +29 -0
- package/dist/server/socket-error-backstop.d.ts +9 -1
- package/dist/server/socket-error-backstop.js +46 -17
- package/dist/server/static-file-signal.d.ts +15 -4
- package/dist/server/static-file-signal.js +46 -12
- package/dist/server/worker-image-optimization.d.ts +34 -0
- package/dist/server/worker-image-optimization.js +86 -0
- package/dist/server/worker-stages.d.ts +1 -1
- package/dist/server/worker-stages.js +2 -2
- package/dist/server/worker-utils.d.ts +8 -3
- package/dist/server/worker-utils.js +12 -7
- package/dist/shims/app-router-scroll.js +4 -1
- package/dist/shims/app-router-tree-context.d.ts +5 -0
- package/dist/shims/app-router-tree-context.js +27 -0
- package/dist/shims/cache-callable-runtime.d.ts +4 -2
- package/dist/shims/cache-callable-runtime.js +21 -12
- package/dist/shims/cache-handler.js +1 -9
- package/dist/shims/cache-runtime.d.ts +6 -1
- package/dist/shims/cache-runtime.js +2 -1
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +40 -13
- package/dist/shims/cdn-cache.d.ts +8 -0
- package/dist/shims/cdn-cache.js +17 -1
- package/dist/shims/disable-smooth-scroll.d.ts +3 -0
- package/dist/shims/disable-smooth-scroll.js +36 -0
- package/dist/shims/document-placeholders.d.ts +19 -0
- package/dist/shims/document-placeholders.js +45 -0
- package/dist/shims/document.js +21 -5
- package/dist/shims/dynamic-preload-chunks.d.ts +1 -0
- package/dist/shims/dynamic-preload-chunks.js +13 -9
- package/dist/shims/dynamic.d.ts +1 -1
- package/dist/shims/dynamic.js +60 -8
- package/dist/shims/fetch-cache-state.d.ts +66 -0
- package/dist/shims/fetch-cache-state.js +92 -0
- package/dist/shims/fetch-cache.d.ts +3 -67
- package/dist/shims/fetch-cache.js +160 -125
- package/dist/shims/head.d.ts +10 -6
- package/dist/shims/head.js +15 -13
- package/dist/shims/image.js +2 -1
- package/dist/shims/internal/work-store-scope.d.ts +5 -0
- package/dist/shims/internal/work-store-scope.js +24 -0
- package/dist/shims/navigation.js +31 -5
- package/dist/shims/request-context.d.ts +2 -0
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/router.js +12 -20
- package/dist/shims/server.d.ts +16 -0
- package/dist/shims/server.js +24 -4
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/url-utils.d.ts +2 -0
- package/dist/shims/url-utils.js +3 -1
- package/dist/utils/client-runtime-metadata.js +1 -1
- package/dist/utils/hash.d.ts +7 -0
- package/dist/utils/hash.js +11 -1
- package/dist/utils/package-name.d.ts +6 -0
- package/dist/utils/package-name.js +12 -1
- package/dist/utils/plugin-rsc-version.d.ts +4 -0
- package/dist/utils/plugin-rsc-version.js +15 -0
- package/dist/utils/prerender-output-paths.js +15 -4
- package/dist/utils/public-file-path.d.ts +10 -2
- package/dist/utils/public-file-path.js +13 -9
- package/dist/utils/public-routes.js +2 -2
- package/dist/utils/react-version.d.ts +3 -0
- package/dist/utils/react-version.js +1 -1
- package/package.json +7 -3
package/dist/shims/dynamic.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
+
import { AppRouterTreeContext } from "./app-router-tree-context.js";
|
|
1
2
|
import { DynamicPreloadChunks } from "./dynamic-preload-chunks.js";
|
|
2
3
|
import React from "react";
|
|
3
4
|
//#region src/shims/dynamic.ts
|
|
4
5
|
/**
|
|
5
6
|
* next/dynamic shim
|
|
6
7
|
*
|
|
7
|
-
* SSR-safe dynamic imports. On the server, uses React.lazy
|
|
8
|
+
* SSR-safe dynamic imports. On the server, uses React.lazy so that
|
|
8
9
|
* renderToReadableStream suspends until the dynamically-imported component is
|
|
9
|
-
* available. On the client, also uses React.lazy for code splitting.
|
|
10
|
+
* available. On the client, also uses React.lazy for code splitting. As in
|
|
11
|
+
* the Next.js App Router, a Suspense boundary is added only for `ssr: false`
|
|
12
|
+
* or an explicit `loading` component. Other trees (Pages Router) keep it.
|
|
10
13
|
*
|
|
11
14
|
* Works in RSC, SSR, and client environments:
|
|
12
|
-
* - RSC: Uses React.lazy
|
|
15
|
+
* - RSC: Uses React.lazy (available in React 19.x react-server).
|
|
13
16
|
* Falls back to async component pattern if a future React version
|
|
14
17
|
* strips lazy from react-server.
|
|
15
|
-
* - SSR: React.lazy
|
|
16
|
-
* - Client: React.lazy
|
|
18
|
+
* - SSR: React.lazy (renderToReadableStream suspends)
|
|
19
|
+
* - Client: React.lazy (standard code splitting)
|
|
17
20
|
*
|
|
18
21
|
* Supports:
|
|
19
22
|
* - dynamic(import('./Component'))
|
|
@@ -115,8 +118,55 @@ function getDynamicErrorBoundary() {
|
|
|
115
118
|
}
|
|
116
119
|
const isServer = typeof window === "undefined";
|
|
117
120
|
/**
|
|
121
|
+
* Whether this dynamic() renders in an App Router tree. RSC renders the App
|
|
122
|
+
* Router only, and react-server has no context support. On the server, the
|
|
123
|
+
* App Router SSR entry marks its tree; in the browser, App Router documents
|
|
124
|
+
* set `window.next.appDir` before anything renders, which also covers
|
|
125
|
+
* separate client roots (e.g. a modal rendered with createRoot). Everything
|
|
126
|
+
* else (Pages Router pages, `pages/_document`, ad-hoc react-dom/server
|
|
127
|
+
* renders) keeps the boundary, since Pages next/dynamic is react-loadable,
|
|
128
|
+
* which never suspends.
|
|
129
|
+
*/
|
|
130
|
+
function useIsAppRouterTree() {
|
|
131
|
+
if (!isServer) return window.next?.appDir === true;
|
|
132
|
+
return AppRouterTreeContext ? React.use(AppRouterTreeContext) : true;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The element tree around an SSR-enabled dynamic() component. The client
|
|
136
|
+
* renders empty slots where the server renders the preload chunks, so both
|
|
137
|
+
* sides render the same shape and useId values inside the dynamic component
|
|
138
|
+
* match on hydration.
|
|
139
|
+
*
|
|
140
|
+
* Match Next.js App Router Loadable: the component only gets a Suspense
|
|
141
|
+
* boundary when it has a `loading` component. Without one, the lazy component
|
|
142
|
+
* suspends up to the nearest parent boundary, so the server shell waits for
|
|
143
|
+
* the import instead of flushing an empty boundary and streaming the
|
|
144
|
+
* component in after first paint. Other trees always get the boundary.
|
|
145
|
+
*
|
|
146
|
+
* React hoists the preload links out of place, but a hoisted <link> right
|
|
147
|
+
* after a text node leaves a `<!-- -->` separator behind. Next.js avoids it by
|
|
148
|
+
* hinting scripts with ReactDOM.preload(), which renders nothing. vinext
|
|
149
|
+
* renders real modulepreload links (preloadModule() drops the nonce and
|
|
150
|
+
* fetchPriority), so they go where text rarely precedes them: first inside the
|
|
151
|
+
* boundary, or after the content when there is no boundary (a component whose
|
|
152
|
+
* output ends in text still gets a separator after it). Stylesheets stay
|
|
153
|
+
* before the boundary: a precedence stylesheet inside it makes React outline
|
|
154
|
+
* the boundary even when its content is already resolved, and rendering them
|
|
155
|
+
* ahead of the content keeps their nonce when the content links the same CSS.
|
|
156
|
+
* A dynamic component with CSS right after text therefore still gets the
|
|
157
|
+
* separator.
|
|
158
|
+
*/
|
|
159
|
+
function createDynamicBoundary(fallback, content, preloadModuleIds, hasBoundary) {
|
|
160
|
+
const preloadChunks = (assets) => isServer ? React.createElement(DynamicPreloadChunks, {
|
|
161
|
+
moduleIds: preloadModuleIds,
|
|
162
|
+
assets
|
|
163
|
+
}) : null;
|
|
164
|
+
if (!hasBoundary) return React.createElement(React.Fragment, null, preloadChunks("styles"), content, preloadChunks("scripts"));
|
|
165
|
+
return React.createElement(React.Fragment, null, preloadChunks("styles"), React.createElement(React.Suspense, { fallback }, preloadChunks("scripts"), content));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
118
168
|
* Retained for the Pages Router render pipeline, which calls this before
|
|
119
|
-
* rendering. Dynamic imports now use React.lazy
|
|
169
|
+
* rendering. Dynamic imports now use React.lazy, so there is no
|
|
120
170
|
* separate preload work to await.
|
|
121
171
|
*/
|
|
122
172
|
function flushPreloads() {
|
|
@@ -170,6 +220,7 @@ function dynamic(dynamicInput, options) {
|
|
|
170
220
|
}
|
|
171
221
|
const LazyServer = createLazyComponent(loader);
|
|
172
222
|
const ServerDynamic = (props) => {
|
|
223
|
+
const isAppRouterTree = useIsAppRouterTree();
|
|
173
224
|
const fallback = LoadingComponent ? React.createElement(LoadingComponent, createDynamicLoadingProps()) : null;
|
|
174
225
|
const lazyElement = createElementWithProps(LazyServer, props);
|
|
175
226
|
let content = lazyElement;
|
|
@@ -181,7 +232,7 @@ function dynamic(dynamicInput, options) {
|
|
|
181
232
|
resetKey: 0
|
|
182
233
|
}, lazyElement);
|
|
183
234
|
}
|
|
184
|
-
return
|
|
235
|
+
return createDynamicBoundary(fallback, content, preloadModuleIds, LoadingComponent != null || !isAppRouterTree);
|
|
185
236
|
};
|
|
186
237
|
ServerDynamic.displayName = "DynamicServer";
|
|
187
238
|
return ServerDynamic;
|
|
@@ -189,6 +240,7 @@ function dynamic(dynamicInput, options) {
|
|
|
189
240
|
const InitialLazyComponent = createLazyComponent(loader);
|
|
190
241
|
const ClientDynamic = (props) => {
|
|
191
242
|
const { LazyComponent, retry, retryKey } = useRetryableLazyComponent(loader, InitialLazyComponent);
|
|
243
|
+
const isAppRouterTree = useIsAppRouterTree();
|
|
192
244
|
const fallback = LoadingComponent ? React.createElement(LoadingComponent, createDynamicLoadingProps({ retry })) : null;
|
|
193
245
|
const lazyElement = createElementWithProps(LazyComponent, props);
|
|
194
246
|
let content = lazyElement;
|
|
@@ -200,7 +252,7 @@ function dynamic(dynamicInput, options) {
|
|
|
200
252
|
resetKey: retryKey
|
|
201
253
|
}, lazyElement);
|
|
202
254
|
}
|
|
203
|
-
return
|
|
255
|
+
return createDynamicBoundary(fallback, content, preloadModuleIds, LoadingComponent != null || !isAppRouterTree);
|
|
204
256
|
};
|
|
205
257
|
ClientDynamic.displayName = "DynamicClient";
|
|
206
258
|
return ClientDynamic;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/shims/fetch-cache-state.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Request-scoped fetch cache state, kept apart from the fetch patching in
|
|
4
|
+
* fetch-cache.ts so modules that only read or update it, like next/cache,
|
|
5
|
+
* don't pull the patched fetch and its Node.js builtins into client graphs
|
|
6
|
+
* that import them.
|
|
7
|
+
*/
|
|
8
|
+
export type FetchDedupeEntry = {
|
|
9
|
+
key: string;
|
|
10
|
+
promise: Promise<Response>;
|
|
11
|
+
response: Response | null;
|
|
12
|
+
};
|
|
13
|
+
export type FetchCacheState = {
|
|
14
|
+
cacheableFetchUrls: Set<string>;
|
|
15
|
+
currentRequestTags: string[];
|
|
16
|
+
currentFetchSoftTags: string[];
|
|
17
|
+
currentFetchCacheMode: FetchCacheMode | null;
|
|
18
|
+
currentFetchRevalidate: number | null;
|
|
19
|
+
currentForceDynamicFetchDefault: boolean;
|
|
20
|
+
dynamicFetchUrls: Set<string>;
|
|
21
|
+
refreshStaleFetchesInForeground: boolean;
|
|
22
|
+
isFetchDedupeActive: boolean;
|
|
23
|
+
currentFetchDedupeEntries: Map<string, FetchDedupeEntry[]>;
|
|
24
|
+
nextFetchId: number;
|
|
25
|
+
};
|
|
26
|
+
export type FetchCacheMode = "auto" | "default-cache" | "default-no-store" | "force-cache" | "force-no-store" | "only-cache" | "only-no-store";
|
|
27
|
+
export declare const fetchCacheAls: import("node:async_hooks").AsyncLocalStorage<FetchCacheState>;
|
|
28
|
+
/**
|
|
29
|
+
* Process-wide state used only while the deprecated `withFetchCache()` is
|
|
30
|
+
* active, which marks it with `isFetchDedupeActive`.
|
|
31
|
+
*/
|
|
32
|
+
export declare const fallbackFetchCacheState: FetchCacheState;
|
|
33
|
+
export declare function getFetchCacheState(): FetchCacheState;
|
|
34
|
+
/**
|
|
35
|
+
* Reset the fallback state for a new request. Used by `withFetchCache()`
|
|
36
|
+
* in single-threaded contexts where ALS.run() isn't used.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resetFallbackFetchCacheState(isFetchDedupeActive: boolean): void;
|
|
39
|
+
/**
|
|
40
|
+
* Append cache tags to the current request's collected tags.
|
|
41
|
+
*
|
|
42
|
+
* Mirrors Next.js's `propagateCacheLifeAndTagsToRevalidateStore`: tags declared
|
|
43
|
+
* inside a `"use cache"` function (via `cacheTag()`, persisted on the data cache
|
|
44
|
+
* entry) must also bubble up to the surrounding page / route-handler ISR entry
|
|
45
|
+
* so `revalidateTag()` / `revalidatePath()` can evict the rendered output, not
|
|
46
|
+
* just the inner data cache entry. Without this, a cached `"use cache"` result
|
|
47
|
+
* keeps being served from a stale page/route entry after its tag is revalidated
|
|
48
|
+
* (issue #1453). Tags are already encoded by the caller; deduped to match the
|
|
49
|
+
* tagged-fetch path. A no-op for empty input.
|
|
50
|
+
*/
|
|
51
|
+
export declare function addCollectedRequestTags(tags: readonly string[]): void;
|
|
52
|
+
/**
|
|
53
|
+
* Read the path-derived soft tags for the current render.
|
|
54
|
+
*
|
|
55
|
+
* Used by the "use cache" runtime to pass soft tags to the cache handler
|
|
56
|
+
* so that `revalidatePath()` invalidates "use cache" entries during the
|
|
57
|
+
* affected route's next request, even when the entry carries no hard tags.
|
|
58
|
+
*/
|
|
59
|
+
export declare function getCurrentFetchSoftTags(): string[];
|
|
60
|
+
/**
|
|
61
|
+
* Run `fn` with the request's fetch settings but its own record of the tags and
|
|
62
|
+
* URLs its fetches touch, so work done on the request's behalf after the fact
|
|
63
|
+
* (a background regeneration) leaves the request's response untouched.
|
|
64
|
+
*/
|
|
65
|
+
export declare function runWithDetachedFetchObservations<T>(fn: () => Promise<T>): Promise<T>;
|
|
66
|
+
//#endregion
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { getOrCreateAls } from "./internal/als-registry.js";
|
|
2
|
+
import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation } from "./unified-request-context.js";
|
|
3
|
+
//#region src/shims/fetch-cache-state.ts
|
|
4
|
+
/**
|
|
5
|
+
* Request-scoped fetch cache state, kept apart from the fetch patching in
|
|
6
|
+
* fetch-cache.ts so modules that only read or update it, like next/cache,
|
|
7
|
+
* don't pull the patched fetch and its Node.js builtins into client graphs
|
|
8
|
+
* that import them.
|
|
9
|
+
*/
|
|
10
|
+
const _FALLBACK_KEY = Symbol.for("vinext.fetchCache.fallback");
|
|
11
|
+
const fetchCacheAls = getOrCreateAls("vinext.fetchCache.als");
|
|
12
|
+
function createFetchCacheState() {
|
|
13
|
+
return {
|
|
14
|
+
cacheableFetchUrls: /* @__PURE__ */ new Set(),
|
|
15
|
+
currentRequestTags: [],
|
|
16
|
+
currentFetchSoftTags: [],
|
|
17
|
+
currentFetchCacheMode: null,
|
|
18
|
+
currentFetchRevalidate: null,
|
|
19
|
+
currentForceDynamicFetchDefault: false,
|
|
20
|
+
dynamicFetchUrls: /* @__PURE__ */ new Set(),
|
|
21
|
+
refreshStaleFetchesInForeground: false,
|
|
22
|
+
isFetchDedupeActive: false,
|
|
23
|
+
currentFetchDedupeEntries: /* @__PURE__ */ new Map(),
|
|
24
|
+
nextFetchId: 1
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Process-wide state used only while the deprecated `withFetchCache()` is
|
|
29
|
+
* active, which marks it with `isFetchDedupeActive`.
|
|
30
|
+
*/
|
|
31
|
+
const fallbackFetchCacheState = globalThis[_FALLBACK_KEY] ??= createFetchCacheState();
|
|
32
|
+
function getFetchCacheState() {
|
|
33
|
+
if (isInsideUnifiedScope()) return getRequestContext();
|
|
34
|
+
const store = fetchCacheAls.getStore();
|
|
35
|
+
if (store) return store;
|
|
36
|
+
if (fallbackFetchCacheState.isFetchDedupeActive) return fallbackFetchCacheState;
|
|
37
|
+
return createFetchCacheState();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Reset the fallback state for a new request. Used by `withFetchCache()`
|
|
41
|
+
* in single-threaded contexts where ALS.run() isn't used.
|
|
42
|
+
*/
|
|
43
|
+
function resetFallbackFetchCacheState(isFetchDedupeActive) {
|
|
44
|
+
Object.assign(fallbackFetchCacheState, createFetchCacheState(), { isFetchDedupeActive });
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Append cache tags to the current request's collected tags.
|
|
48
|
+
*
|
|
49
|
+
* Mirrors Next.js's `propagateCacheLifeAndTagsToRevalidateStore`: tags declared
|
|
50
|
+
* inside a `"use cache"` function (via `cacheTag()`, persisted on the data cache
|
|
51
|
+
* entry) must also bubble up to the surrounding page / route-handler ISR entry
|
|
52
|
+
* so `revalidateTag()` / `revalidatePath()` can evict the rendered output, not
|
|
53
|
+
* just the inner data cache entry. Without this, a cached `"use cache"` result
|
|
54
|
+
* keeps being served from a stale page/route entry after its tag is revalidated
|
|
55
|
+
* (issue #1453). Tags are already encoded by the caller; deduped to match the
|
|
56
|
+
* tagged-fetch path. A no-op for empty input.
|
|
57
|
+
*/
|
|
58
|
+
function addCollectedRequestTags(tags) {
|
|
59
|
+
if (tags.length === 0) return;
|
|
60
|
+
const reqTags = getFetchCacheState().currentRequestTags;
|
|
61
|
+
for (const tag of tags) if (!reqTags.includes(tag)) reqTags.push(tag);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Read the path-derived soft tags for the current render.
|
|
65
|
+
*
|
|
66
|
+
* Used by the "use cache" runtime to pass soft tags to the cache handler
|
|
67
|
+
* so that `revalidatePath()` invalidates "use cache" entries during the
|
|
68
|
+
* affected route's next request, even when the entry carries no hard tags.
|
|
69
|
+
*/
|
|
70
|
+
function getCurrentFetchSoftTags() {
|
|
71
|
+
return getFetchCacheState().currentFetchSoftTags;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Run `fn` with the request's fetch settings but its own record of the tags and
|
|
75
|
+
* URLs its fetches touch, so work done on the request's behalf after the fact
|
|
76
|
+
* (a background regeneration) leaves the request's response untouched.
|
|
77
|
+
*/
|
|
78
|
+
function runWithDetachedFetchObservations(fn) {
|
|
79
|
+
if (isInsideUnifiedScope()) return runWithUnifiedStateMutation((uCtx) => {
|
|
80
|
+
uCtx.cacheableFetchUrls = /* @__PURE__ */ new Set();
|
|
81
|
+
uCtx.currentRequestTags = [];
|
|
82
|
+
uCtx.dynamicFetchUrls = /* @__PURE__ */ new Set();
|
|
83
|
+
}, fn);
|
|
84
|
+
return fetchCacheAls.run({
|
|
85
|
+
...getFetchCacheState(),
|
|
86
|
+
cacheableFetchUrls: /* @__PURE__ */ new Set(),
|
|
87
|
+
currentRequestTags: [],
|
|
88
|
+
dynamicFetchUrls: /* @__PURE__ */ new Set()
|
|
89
|
+
}, fn);
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { addCollectedRequestTags, fallbackFetchCacheState, fetchCacheAls, getCurrentFetchSoftTags, getFetchCacheState, resetFallbackFetchCacheState, runWithDetachedFetchObservations };
|
|
@@ -1,33 +1,9 @@
|
|
|
1
|
+
import { FetchCacheMode, FetchCacheState, addCollectedRequestTags, getCurrentFetchSoftTags, runWithDetachedFetchObservations } from "./fetch-cache-state.js";
|
|
1
2
|
//#region src/shims/fetch-cache.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Extended fetch() with Next.js caching semantics.
|
|
4
|
-
*
|
|
5
|
-
* Patches `globalThis.fetch` during server rendering to support:
|
|
6
|
-
*
|
|
7
|
-
* fetch(url, { next: { revalidate: 60, tags: ['posts'] } })
|
|
8
|
-
* fetch(url, { cache: 'force-cache' })
|
|
9
|
-
* fetch(url, { cache: 'no-store' })
|
|
10
|
-
*
|
|
11
|
-
* Cached responses are stored via the pluggable CacheHandler, so
|
|
12
|
-
* revalidateTag() and revalidatePath() invalidate fetch-level caches.
|
|
13
|
-
*
|
|
14
|
-
* Usage (in server entry):
|
|
15
|
-
* import { withFetchCache, cleanupFetchCache } from './fetch-cache';
|
|
16
|
-
* const cleanup = withFetchCache();
|
|
17
|
-
* try { ... render ... } finally { cleanup(); }
|
|
18
|
-
*
|
|
19
|
-
* Or use the async helper:
|
|
20
|
-
* await runWithFetchCache(async () => { ... render ... });
|
|
21
|
-
*/
|
|
22
3
|
type NextFetchOptions = {
|
|
23
4
|
revalidate?: number | false;
|
|
24
5
|
tags?: string[];
|
|
25
6
|
};
|
|
26
|
-
type FetchDedupeEntry = {
|
|
27
|
-
key: string;
|
|
28
|
-
promise: Promise<Response>;
|
|
29
|
-
response: Response | null;
|
|
30
|
-
};
|
|
31
7
|
declare global {
|
|
32
8
|
interface RequestInit {
|
|
33
9
|
next?: NextFetchOptions;
|
|
@@ -35,20 +11,6 @@ declare global {
|
|
|
35
11
|
}
|
|
36
12
|
/** @internal Reset dedup state — exposed for test isolation only. */
|
|
37
13
|
export declare function _resetPendingRefetches(): void;
|
|
38
|
-
export type FetchCacheState = {
|
|
39
|
-
cacheableFetchUrls: Set<string>;
|
|
40
|
-
currentRequestTags: string[];
|
|
41
|
-
currentFetchSoftTags: string[];
|
|
42
|
-
currentFetchCacheMode: FetchCacheMode | null;
|
|
43
|
-
currentFetchRevalidate: number | null;
|
|
44
|
-
currentForceDynamicFetchDefault: boolean;
|
|
45
|
-
dynamicFetchUrls: Set<string>;
|
|
46
|
-
refreshStaleFetchesInForeground: boolean;
|
|
47
|
-
isFetchDedupeActive: boolean;
|
|
48
|
-
currentFetchDedupeEntries: Map<string, FetchDedupeEntry[]>;
|
|
49
|
-
nextFetchId: number;
|
|
50
|
-
};
|
|
51
|
-
export type FetchCacheMode = "auto" | "default-cache" | "default-no-store" | "force-cache" | "force-no-store" | "only-cache" | "only-no-store";
|
|
52
14
|
export declare function peekCacheableFetchObservations(): string[];
|
|
53
15
|
export declare function peekDynamicFetchObservations(): string[];
|
|
54
16
|
export declare function consumeDynamicFetchObservations(): string[];
|
|
@@ -58,19 +20,6 @@ export declare function consumeDynamicFetchObservations(): string[];
|
|
|
58
20
|
* fetch tags used during rendering.
|
|
59
21
|
*/
|
|
60
22
|
export declare function getCollectedFetchTags(): string[];
|
|
61
|
-
/**
|
|
62
|
-
* Append cache tags to the current request's collected tags.
|
|
63
|
-
*
|
|
64
|
-
* Mirrors Next.js's `propagateCacheLifeAndTagsToRevalidateStore`: tags declared
|
|
65
|
-
* inside a `"use cache"` function (via `cacheTag()`, persisted on the data cache
|
|
66
|
-
* entry) must also bubble up to the surrounding page / route-handler ISR entry
|
|
67
|
-
* so `revalidateTag()` / `revalidatePath()` can evict the rendered output, not
|
|
68
|
-
* just the inner data cache entry. Without this, a cached `"use cache"` result
|
|
69
|
-
* keeps being served from a stale page/route entry after its tag is revalidated
|
|
70
|
-
* (issue #1453). Tags are already encoded by the caller; deduped to match the
|
|
71
|
-
* tagged-fetch path. A no-op for empty input.
|
|
72
|
-
*/
|
|
73
|
-
export declare function addCollectedRequestTags(tags: readonly string[]): void;
|
|
74
23
|
/**
|
|
75
24
|
* Set path-derived implicit tags for fetch cache reads in the current render.
|
|
76
25
|
*
|
|
@@ -79,14 +28,6 @@ export declare function addCollectedRequestTags(tags: readonly string[]): void;
|
|
|
79
28
|
* affected route, without permanently coupling a shared fetch entry to one path.
|
|
80
29
|
*/
|
|
81
30
|
export declare function setCurrentFetchSoftTags(tags: string[]): void;
|
|
82
|
-
/**
|
|
83
|
-
* Read the path-derived soft tags for the current render.
|
|
84
|
-
*
|
|
85
|
-
* Used by the "use cache" runtime to pass soft tags to the cache handler
|
|
86
|
-
* so that `revalidatePath()` invalidates "use cache" entries during the
|
|
87
|
-
* affected route's next request, even when the entry carries no hard tags.
|
|
88
|
-
*/
|
|
89
|
-
export declare function getCurrentFetchSoftTags(): string[];
|
|
90
31
|
export declare function setCurrentFetchCacheMode(mode: FetchCacheMode | null): void;
|
|
91
32
|
export declare function setCurrentFetchRevalidate(revalidate: number | null): void;
|
|
92
33
|
export declare function setCurrentForceDynamicFetchDefault(enabled: boolean): void;
|
|
@@ -103,12 +44,6 @@ export declare function setRefreshStaleFetchesInForeground(enabled: boolean): vo
|
|
|
103
44
|
* try { await render(); } finally { cleanup(); }
|
|
104
45
|
*/
|
|
105
46
|
export declare function withFetchCache(): () => void;
|
|
106
|
-
/**
|
|
107
|
-
* Run `fn` with the request's fetch settings but its own record of the tags and
|
|
108
|
-
* URLs its fetches touch, so work done on the request's behalf after the fact
|
|
109
|
-
* (a background regeneration) leaves the request's response untouched.
|
|
110
|
-
*/
|
|
111
|
-
export declare function runWithDetachedFetchObservations<T>(fn: () => Promise<T>): Promise<T>;
|
|
112
47
|
/**
|
|
113
48
|
* Run an async function with patched fetch caching enabled.
|
|
114
49
|
* Uses `AsyncLocalStorage.run()` for proper per-request isolation
|
|
@@ -143,4 +78,5 @@ export declare function ensureFetchPatch(): void;
|
|
|
143
78
|
* Useful for internal code that should bypass caching.
|
|
144
79
|
*/
|
|
145
80
|
export declare function getOriginalFetch(): typeof globalThis.fetch;
|
|
146
|
-
//#endregion
|
|
81
|
+
//#endregion
|
|
82
|
+
export { type FetchCacheMode, type FetchCacheState, addCollectedRequestTags, getCurrentFetchSoftTags, runWithDetachedFetchObservations };
|