vinext 0.2.0 → 0.2.1
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/dist/build/css-url-assets.d.ts +3 -1
- package/dist/build/css-url-assets.js +18 -1
- package/dist/build/inject-pregenerated-paths.d.ts +3 -0
- package/dist/build/inject-pregenerated-paths.js +4 -1
- package/dist/build/prerender-server-entry.d.ts +1 -0
- package/dist/build/prerender-server-entry.js +49 -0
- package/dist/build/prerender-server-pool.d.ts +44 -0
- package/dist/build/prerender-server-pool.js +194 -0
- package/dist/build/prerender.js +86 -22
- package/dist/build/run-prerender.js +2 -1
- package/dist/check.d.ts +4 -6
- package/dist/check.js +8 -9
- package/dist/cli.js +1 -1
- package/dist/client/vinext-next-data.d.ts +4 -1
- package/dist/config/config-matchers.js +33 -11
- package/dist/config/next-config.d.ts +36 -6
- package/dist/config/next-config.js +16 -2
- package/dist/entries/app-browser-entry.js +5 -1
- package/dist/entries/app-rsc-entry.d.ts +3 -2
- package/dist/entries/app-rsc-entry.js +4 -0
- package/dist/entries/pages-client-entry.js +14 -3
- package/dist/entries/pages-server-entry.js +18 -4
- package/dist/index.js +320 -25
- package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.js +8 -1
- package/dist/packages/cloudflare/src/deploy.js +1 -5
- package/dist/packages/cloudflare/src/tpr.js +26 -5
- package/dist/plugins/fonts.js +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +1 -1
- package/dist/plugins/og-assets.js +2 -1
- package/dist/plugins/optimize-imports.js +1 -1
- package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
- package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
- package/dist/plugins/sass.d.ts +17 -1
- package/dist/plugins/sass.js +74 -1
- package/dist/plugins/styled-jsx.d.ts +16 -0
- package/dist/plugins/styled-jsx.js +149 -0
- package/dist/routing/app-route-graph.js +22 -16
- package/dist/routing/file-matcher.d.ts +8 -1
- package/dist/routing/file-matcher.js +15 -3
- package/dist/server/app-browser-entry.js +46 -14
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-browser-server-action-client.js +5 -3
- package/dist/server/app-browser-state.d.ts +1 -0
- package/dist/server/app-browser-state.js +2 -2
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-page-boundary.js +2 -1
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +3 -3
- package/dist/server/app-page-cache.js +23 -6
- package/dist/server/app-page-dispatch.d.ts +1 -0
- package/dist/server/app-page-dispatch.js +25 -8
- package/dist/server/app-page-element-builder.js +1 -0
- package/dist/server/app-page-execution.js +2 -1
- package/dist/server/app-page-render-identity.d.ts +1 -0
- package/dist/server/app-page-render-identity.js +2 -1
- package/dist/server/app-page-render.d.ts +2 -0
- package/dist/server/app-page-render.js +67 -16
- package/dist/server/app-page-response.d.ts +7 -0
- package/dist/server/app-page-response.js +16 -4
- package/dist/server/app-page-stream.d.ts +2 -1
- package/dist/server/app-page-stream.js +1 -1
- package/dist/server/app-route-handler-execution.js +1 -1
- package/dist/server/app-route-tree-prefetch.d.ts +43 -0
- package/dist/server/app-route-tree-prefetch.js +187 -0
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +2 -1
- package/dist/server/app-rsc-cache-busting.js +9 -4
- package/dist/server/app-rsc-handler.d.ts +6 -0
- package/dist/server/app-rsc-handler.js +89 -11
- package/dist/server/app-rsc-render-mode.d.ts +3 -2
- package/dist/server/app-rsc-render-mode.js +4 -1
- package/dist/server/app-rsc-request-normalization.d.ts +3 -4
- package/dist/server/app-rsc-request-normalization.js +4 -5
- package/dist/server/app-server-action-execution.js +4 -3
- package/dist/server/app-ssr-entry.js +3 -3
- package/dist/server/cache-control.d.ts +3 -1
- package/dist/server/cache-control.js +13 -1
- package/dist/server/dev-server.d.ts +11 -1
- package/dist/server/dev-server.js +78 -20
- package/dist/server/headers.d.ts +6 -2
- package/dist/server/headers.js +11 -5
- package/dist/server/isr-cache.d.ts +2 -1
- package/dist/server/isr-cache.js +7 -3
- package/dist/server/pages-data-route.d.ts +4 -2
- package/dist/server/pages-data-route.js +18 -4
- package/dist/server/pages-dev-module-url.d.ts +2 -1
- package/dist/server/pages-dev-module-url.js +6 -3
- package/dist/server/pages-node-compat.d.ts +12 -1
- package/dist/server/pages-node-compat.js +50 -1
- package/dist/server/pages-page-data.d.ts +9 -0
- package/dist/server/pages-page-data.js +17 -9
- package/dist/server/pages-page-handler.js +19 -7
- package/dist/server/pages-page-response.d.ts +1 -0
- package/dist/server/pages-page-response.js +3 -2
- package/dist/server/pages-request-pipeline.d.ts +8 -6
- package/dist/server/pages-request-pipeline.js +30 -6
- package/dist/server/pages-router-entry.js +1 -1
- package/dist/server/prod-server.d.ts +4 -2
- package/dist/server/prod-server.js +38 -22
- package/dist/server/request-pipeline.js +1 -1
- package/dist/shims/cache-handler.js +8 -1
- package/dist/shims/cache.js +3 -0
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +77 -52
- package/dist/shims/form.d.ts +1 -1
- package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
- package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -1
- package/dist/shims/internal/hybrid-client-route-owner.js +34 -1
- package/dist/shims/internal/pages-data-fetch-dedup.d.ts +2 -1
- package/dist/shims/internal/pages-data-fetch-dedup.js +13 -2
- package/dist/shims/internal/pages-data-target.d.ts +8 -3
- package/dist/shims/internal/pages-data-target.js +9 -4
- package/dist/shims/link.d.ts +1 -1
- package/dist/shims/link.js +179 -42
- package/dist/shims/navigation.d.ts +15 -3
- package/dist/shims/navigation.js +202 -39
- package/dist/shims/navigation.react-server.js +1 -1
- package/dist/shims/request-context.js +18 -0
- package/dist/shims/router.js +31 -15
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -1
- package/dist/utils/middleware-request-headers.js +1 -1
- package/dist/utils/protocol-headers.d.ts +7 -1
- package/dist/utils/protocol-headers.js +7 -1
- package/dist/utils/vite-version.d.ts +2 -0
- package/dist/utils/vite-version.js +11 -1
- package/package.json +2 -2
package/dist/shims/link.js
CHANGED
|
@@ -13,6 +13,7 @@ import { getCurrentRoutePathnameForWarning } from "./internal/route-pattern-for-
|
|
|
13
13
|
import { isBotUserAgent } from "../utils/html-limited-bots.js";
|
|
14
14
|
import { getNavigationRuntime, hasAppNavigationRuntime, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
|
|
15
15
|
import { navigatePagesRouterLinkWithFallback, resolvePagesRouterQueryOnlyHref } from "../client/pages-router-link-navigation.js";
|
|
16
|
+
import { scheduleAppPrefetchFetch } from "./internal/app-prefetch-fetch-queue.js";
|
|
16
17
|
import { getI18nContext } from "./i18n-context.js";
|
|
17
18
|
import { canLinkIntentPrefetch, canLinkPrefetch, getLinkPrefetchHref } from "./link-prefetch.js";
|
|
18
19
|
import { clearLinkForCurrentNavigation, notifyLinkNavigationStart, setLinkForCurrentNavigation } from "./internal/link-status-registry.js";
|
|
@@ -138,7 +139,7 @@ function getLinkPrefetchRouterMode() {
|
|
|
138
139
|
}
|
|
139
140
|
function resolveMatchedAutoAppRoutePrefetch(route) {
|
|
140
141
|
return {
|
|
141
|
-
cacheForNavigation: !route.canPrefetchLoadingShell,
|
|
142
|
+
cacheForNavigation: !route.canPrefetchLoadingShell && route.requiresDynamicNavigationRequest !== true,
|
|
142
143
|
prefetchShellFirst: !route.isDynamic,
|
|
143
144
|
shouldPrefetch: true
|
|
144
145
|
};
|
|
@@ -149,9 +150,8 @@ function canAutoPrefetchFullAppRoute(href) {
|
|
|
149
150
|
if (!routes) return false;
|
|
150
151
|
const routeHref = toSameOriginRouteHref(href);
|
|
151
152
|
if (routeHref === null) return false;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return resolveMatchedAutoAppRoutePrefetch(match.route).cacheForNavigation;
|
|
153
|
+
if (!matchRouteWithTrie(routeHref, routes, linkPrefetchRouteTrieCache)) return false;
|
|
154
|
+
return resolveAutoAppRoutePrefetch(href).cacheForNavigation;
|
|
155
155
|
}
|
|
156
156
|
function resolveAutoAppRoutePrefetch(href) {
|
|
157
157
|
if (typeof window === "undefined") return {
|
|
@@ -177,7 +177,20 @@ function resolveAutoAppRoutePrefetch(href) {
|
|
|
177
177
|
prefetchShellFirst: false,
|
|
178
178
|
shouldPrefetch: false
|
|
179
179
|
};
|
|
180
|
-
|
|
180
|
+
const prefetch = resolveMatchedAutoAppRoutePrefetch(match.route);
|
|
181
|
+
if (new URL(routeHref, "http://vinext.local").search !== "") return {
|
|
182
|
+
...prefetch,
|
|
183
|
+
cacheForNavigation: false,
|
|
184
|
+
prefetchShellFirst: true
|
|
185
|
+
};
|
|
186
|
+
return prefetch;
|
|
187
|
+
}
|
|
188
|
+
function resolveFullAppRoutePrefetch() {
|
|
189
|
+
return {
|
|
190
|
+
cacheForNavigation: true,
|
|
191
|
+
prefetchShellFirst: true,
|
|
192
|
+
shouldPrefetch: true
|
|
193
|
+
};
|
|
181
194
|
}
|
|
182
195
|
/**
|
|
183
196
|
* Prefetch a URL for faster navigation.
|
|
@@ -187,10 +200,11 @@ function resolveAutoAppRoutePrefetch(href) {
|
|
|
187
200
|
* For Pages Router: warms the page chunk, prefetches data only for SSG pages,
|
|
188
201
|
* and falls back to a document prefetch hint when no page loader matches.
|
|
189
202
|
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
203
|
+
* App Router and high-priority prefetches start immediately. Low-priority
|
|
204
|
+
* Pages Router fallback prefetches use `requestIdleCallback` (or `setTimeout`
|
|
205
|
+
* fallback) to avoid blocking the main thread during initial page load.
|
|
192
206
|
*/
|
|
193
|
-
function prefetchUrl(href, mode, priority = "low", pagesRouteHref) {
|
|
207
|
+
function prefetchUrl(href, mode, priority = "low", pagesRouteHref, locale) {
|
|
194
208
|
if (typeof window === "undefined") return;
|
|
195
209
|
const prefetchHref = getLinkPrefetchHref({
|
|
196
210
|
href,
|
|
@@ -206,13 +220,11 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref) {
|
|
|
206
220
|
}) ?? prefetchHref, window.location.href, __basePath);
|
|
207
221
|
const target = new URL(fullHref, window.location.href);
|
|
208
222
|
if (target.origin === window.location.origin && target.pathname === window.location.pathname && target.search === window.location.search) return;
|
|
209
|
-
|
|
210
|
-
fn();
|
|
211
|
-
} : window.requestIdleCallback ?? ((fn) => setTimeout(fn, 100)))(() => {
|
|
223
|
+
const runPrefetch = () => {
|
|
212
224
|
(async () => {
|
|
213
225
|
if (hasAppNavigationRuntime()) {
|
|
214
226
|
if (isBotUserAgent(window.navigator?.userAgent ?? "")) return;
|
|
215
|
-
const [navigation, { AppElementsWire }, rscCacheBusting, { APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL }, headersModule, { resolveHybridClientRouteOwner }] = await Promise.all([
|
|
227
|
+
const [navigation, { AppElementsWire }, rscCacheBusting, { APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL }, headersModule, { resolveHybridClientRewriteHref, resolveHybridClientRouteOwner }] = await Promise.all([
|
|
216
228
|
import("./navigation.js"),
|
|
217
229
|
import("../server/app-elements.js"),
|
|
218
230
|
import("../server/app-rsc-cache-busting.js"),
|
|
@@ -220,28 +232,40 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref) {
|
|
|
220
232
|
import("../server/headers.js"),
|
|
221
233
|
import("./internal/hybrid-client-route-owner.js")
|
|
222
234
|
]);
|
|
223
|
-
const { getPrefetchInterceptionContext, getPrefetchCache, getPrefetchedUrls, getMountedSlotsHeader, hasPrefetchCacheEntryForNavigation, prefetchRscResponse, PREFETCH_CACHE_TTL } = navigation;
|
|
235
|
+
const { getPrefetchInterceptionContext, getPrefetchCache, getPrefetchedUrls, getMountedSlotsHeader, hasSearchAgnosticPrefetchShellForRoute, hasPrefetchCacheEntryForNavigation, peekPrefetchResponseForNavigation, prefetchRscResponse, restoreRscResponse, PREFETCH_CACHE_TTL } = navigation;
|
|
224
236
|
const { createRscRequestHeaders, createRscRequestUrl } = rscCacheBusting;
|
|
225
|
-
const { NEXT_ROUTER_PREFETCH_HEADER, VINEXT_MOUNTED_SLOTS_HEADER } = headersModule;
|
|
237
|
+
const { NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, VINEXT_MOUNTED_SLOTS_HEADER } = headersModule;
|
|
226
238
|
const hybridOwner = resolveHybridClientRouteOwner(prefetchHref, __basePath);
|
|
227
239
|
if (hybridOwner === "pages" || hybridOwner === "document") return;
|
|
228
|
-
const
|
|
240
|
+
const rewrittenPrefetchHref = resolveHybridClientRewriteHref(fullHref, __basePath);
|
|
241
|
+
const autoPrefetch = mode === "auto" ? resolveAutoAppRoutePrefetch(rewrittenPrefetchHref ?? prefetchHref) : mode === "full-after-shell" ? {
|
|
229
242
|
cacheForNavigation: true,
|
|
230
243
|
prefetchShellFirst: true,
|
|
231
244
|
shouldPrefetch: true
|
|
232
|
-
};
|
|
245
|
+
} : resolveFullAppRoutePrefetch();
|
|
233
246
|
if (!autoPrefetch.shouldPrefetch) return;
|
|
234
247
|
const interceptionContext = getPrefetchInterceptionContext(fullHref);
|
|
235
248
|
const mountedSlotsHeader = getMountedSlotsHeader();
|
|
236
249
|
const isOptimisticRouteShellPrefetch = !autoPrefetch.cacheForNavigation;
|
|
250
|
+
const hasSearchParams = new URL(fullHref, window.location.href).search !== "";
|
|
251
|
+
const isAutomaticSearchParamShell = mode === "auto" && isOptimisticRouteShellPrefetch && hasSearchParams;
|
|
237
252
|
if (isOptimisticRouteShellPrefetch && interceptionContext !== null) return;
|
|
253
|
+
const hasSearchAgnosticShell = isAutomaticSearchParamShell && hasSearchAgnosticPrefetchShellForRoute(await createRscRequestUrl(fullHref, new Headers()), interceptionContext, mountedSlotsHeader);
|
|
238
254
|
const headers = createRscRequestHeaders({
|
|
239
255
|
interceptionContext,
|
|
240
|
-
renderMode: isOptimisticRouteShellPrefetch ? APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL : void 0
|
|
256
|
+
renderMode: isOptimisticRouteShellPrefetch ? hasSearchAgnosticShell ? APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL : isAutomaticSearchParamShell ? APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL : APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL : void 0
|
|
241
257
|
});
|
|
242
258
|
if (mountedSlotsHeader) headers.set(VINEXT_MOUNTED_SLOTS_HEADER, mountedSlotsHeader);
|
|
243
|
-
|
|
259
|
+
const shouldSendSegmentPrefetchHeaders = isOptimisticRouteShellPrefetch || mode === "auto";
|
|
260
|
+
if (__prefetchInlining && autoPrefetch.cacheForNavigation) {
|
|
261
|
+
headers.set(NEXT_ROUTER_PREFETCH_HEADER, "1");
|
|
262
|
+
headers.set(NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, "/__PAGE__");
|
|
263
|
+
} else if (shouldSendSegmentPrefetchHeaders) {
|
|
264
|
+
headers.set(NEXT_ROUTER_PREFETCH_HEADER, "1");
|
|
265
|
+
headers.set(NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, "1");
|
|
266
|
+
}
|
|
244
267
|
const rscUrl = await createRscRequestUrl(fullHref, headers);
|
|
268
|
+
const additionalRscUrls = rewrittenPrefetchHref && rewrittenPrefetchHref !== fullHref ? [await createRscRequestUrl(rewrittenPrefetchHref, headers)] : [];
|
|
245
269
|
const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
|
|
246
270
|
const prefetched = getPrefetchedUrls();
|
|
247
271
|
if (prefetched.has(cacheKey)) {
|
|
@@ -249,41 +273,122 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref) {
|
|
|
249
273
|
const existing = getPrefetchCache().get(cacheKey);
|
|
250
274
|
if (existing?.cacheForNavigation === false) existing.cacheForNavigation = true;
|
|
251
275
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
276
|
+
const fetchFullRscPayload = () => scheduleAppPrefetchFetch(() => fetch(rscUrl, {
|
|
277
|
+
headers,
|
|
278
|
+
credentials: "include",
|
|
279
|
+
priority,
|
|
280
|
+
purpose: "prefetch"
|
|
281
|
+
}), priority);
|
|
282
|
+
const fetchLoadingShellForReuse = async () => {
|
|
255
283
|
const shellHeaders = createRscRequestHeaders({
|
|
256
284
|
interceptionContext,
|
|
257
285
|
renderMode: APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL
|
|
258
286
|
});
|
|
287
|
+
shellHeaders.set(NEXT_ROUTER_PREFETCH_HEADER, "1");
|
|
288
|
+
shellHeaders.set(NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, "1");
|
|
259
289
|
if (mountedSlotsHeader) shellHeaders.set(VINEXT_MOUNTED_SLOTS_HEADER, mountedSlotsHeader);
|
|
260
290
|
const shellRscUrl = await createRscRequestUrl(fullHref, shellHeaders);
|
|
261
|
-
const
|
|
262
|
-
|
|
291
|
+
const shellCacheKey = AppElementsWire.encodeCacheKey(shellRscUrl, interceptionContext);
|
|
292
|
+
const shellCache = getPrefetchCache();
|
|
293
|
+
let shellEntry = shellCache.get(shellCacheKey);
|
|
294
|
+
if (shellEntry === void 0) {
|
|
295
|
+
getPrefetchedUrls().add(shellCacheKey);
|
|
296
|
+
prefetchRscResponse(shellRscUrl, scheduleAppPrefetchFetch(() => fetch(shellRscUrl, {
|
|
297
|
+
headers: shellHeaders,
|
|
298
|
+
credentials: "include",
|
|
299
|
+
priority,
|
|
300
|
+
purpose: "prefetch"
|
|
301
|
+
}), priority), interceptionContext, mountedSlotsHeader, void 0, {
|
|
302
|
+
cacheForNavigation: false,
|
|
303
|
+
optimisticRouteShell: true,
|
|
304
|
+
prefetchKind: "loading-shell"
|
|
305
|
+
});
|
|
306
|
+
shellEntry = shellCache.get(shellCacheKey);
|
|
307
|
+
}
|
|
308
|
+
await shellEntry?.pending?.catch(() => {});
|
|
309
|
+
};
|
|
310
|
+
const fetchAliasCacheHitProbe = async () => {
|
|
311
|
+
const probeHeaders = createRscRequestHeaders({
|
|
312
|
+
interceptionContext,
|
|
313
|
+
renderMode: APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL
|
|
314
|
+
});
|
|
315
|
+
probeHeaders.set(NEXT_ROUTER_PREFETCH_HEADER, "1");
|
|
316
|
+
probeHeaders.set(NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, "1");
|
|
317
|
+
if (mountedSlotsHeader) probeHeaders.set(VINEXT_MOUNTED_SLOTS_HEADER, mountedSlotsHeader);
|
|
318
|
+
const probeRscUrl = await createRscRequestUrl(fullHref, probeHeaders);
|
|
319
|
+
return fetch(probeRscUrl, {
|
|
320
|
+
method: "HEAD",
|
|
321
|
+
headers: probeHeaders,
|
|
263
322
|
credentials: "include",
|
|
264
323
|
priority,
|
|
265
324
|
purpose: "prefetch"
|
|
266
325
|
});
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
326
|
+
};
|
|
327
|
+
const hasExactNavigationCacheEntry = autoPrefetch.cacheForNavigation && hasPrefetchCacheEntryForNavigation(rscUrl, interceptionContext, mountedSlotsHeader);
|
|
328
|
+
if (hasExactNavigationCacheEntry || autoPrefetch.cacheForNavigation && hasPrefetchCacheEntryForNavigation(rscUrl, interceptionContext, mountedSlotsHeader, { additionalRscUrls })) {
|
|
329
|
+
if (!hasExactNavigationCacheEntry && !prefetched.has(cacheKey) && additionalRscUrls.length > 0 && autoPrefetch.prefetchShellFirst && mountedSlotsHeader === null) {
|
|
330
|
+
prefetched.add(cacheKey);
|
|
331
|
+
fetchAliasCacheHitProbe().then((response) => response.arrayBuffer()).catch(() => {});
|
|
332
|
+
}
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
prefetched.add(cacheKey);
|
|
336
|
+
const gateViaRouteTree = __prefetchInlining && mode === "auto" && autoPrefetch.prefetchShellFirst;
|
|
337
|
+
const gateViaExplicitSearchShell = mode === "full" && hasSearchParams && autoPrefetch.prefetchShellFirst && mountedSlotsHeader === null;
|
|
338
|
+
const gateViaLoadingShell = (mode === "full-after-shell" || gateViaExplicitSearchShell) && autoPrefetch.prefetchShellFirst;
|
|
339
|
+
const fetchPromise = autoPrefetch.cacheForNavigation && (gateViaRouteTree || gateViaLoadingShell) ? (async () => {
|
|
340
|
+
if (gateViaLoadingShell) {
|
|
341
|
+
await fetchLoadingShellForReuse();
|
|
342
|
+
return fetchFullRscPayload();
|
|
343
|
+
}
|
|
344
|
+
const shellHeaders = createRscRequestHeaders({
|
|
345
|
+
interceptionContext,
|
|
346
|
+
renderMode: void 0
|
|
347
|
+
});
|
|
348
|
+
shellHeaders.set(NEXT_ROUTER_PREFETCH_HEADER, "1");
|
|
349
|
+
shellHeaders.set(NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, "/_tree");
|
|
350
|
+
if (mountedSlotsHeader) shellHeaders.set(VINEXT_MOUNTED_SLOTS_HEADER, mountedSlotsHeader);
|
|
351
|
+
const shellRscUrl = await createRscRequestUrl(fullHref, shellHeaders);
|
|
352
|
+
const shellCacheKey = AppElementsWire.encodeCacheKey(shellRscUrl, interceptionContext);
|
|
353
|
+
const shellCache = getPrefetchCache();
|
|
354
|
+
let shellEntry = shellCache.get(shellCacheKey);
|
|
355
|
+
if (shellEntry === void 0) {
|
|
356
|
+
getPrefetchedUrls().add(shellCacheKey);
|
|
357
|
+
prefetchRscResponse(shellRscUrl, scheduleAppPrefetchFetch(() => fetch(shellRscUrl, {
|
|
358
|
+
headers: shellHeaders,
|
|
359
|
+
credentials: "include",
|
|
360
|
+
priority,
|
|
361
|
+
purpose: "prefetch"
|
|
362
|
+
}), priority), interceptionContext, mountedSlotsHeader, void 0, {
|
|
363
|
+
cacheForNavigation: false,
|
|
364
|
+
optimisticRouteShell: false,
|
|
365
|
+
prefetchKind: "route-tree"
|
|
366
|
+
});
|
|
367
|
+
shellEntry = shellCache.get(shellCacheKey);
|
|
368
|
+
}
|
|
369
|
+
await shellEntry?.pending?.catch(() => {});
|
|
370
|
+
const renderedPathAndSearch = shellEntry?.snapshot?.renderedPathAndSearch;
|
|
371
|
+
if (renderedPathAndSearch) {
|
|
372
|
+
const cachedRenderedResponse = peekPrefetchResponseForNavigation(await createRscRequestUrl(renderedPathAndSearch, headers), interceptionContext, mountedSlotsHeader);
|
|
373
|
+
if (cachedRenderedResponse) return restoreRscResponse(cachedRenderedResponse);
|
|
374
|
+
}
|
|
375
|
+
return scheduleAppPrefetchFetch(() => fetch(rscUrl, {
|
|
270
376
|
headers,
|
|
271
377
|
credentials: "include",
|
|
272
378
|
priority,
|
|
273
379
|
purpose: "prefetch"
|
|
274
|
-
});
|
|
275
|
-
})() :
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
priority,
|
|
279
|
-
purpose: "prefetch"
|
|
280
|
-
}), interceptionContext, mountedSlotsHeader, void 0, {
|
|
380
|
+
}), priority);
|
|
381
|
+
})() : fetchFullRscPayload();
|
|
382
|
+
if (mode === "full" && autoPrefetch.cacheForNavigation && autoPrefetch.prefetchShellFirst && mountedSlotsHeader === null && !gateViaExplicitSearchShell) fetchLoadingShellForReuse();
|
|
383
|
+
prefetchRscResponse(rscUrl, fetchPromise, interceptionContext, mountedSlotsHeader, void 0, {
|
|
281
384
|
cacheForNavigation: autoPrefetch.cacheForNavigation,
|
|
282
385
|
fallbackTtlMs: PREFETCH_CACHE_TTL,
|
|
283
|
-
optimisticRouteShell: isOptimisticRouteShellPrefetch
|
|
386
|
+
optimisticRouteShell: isOptimisticRouteShellPrefetch,
|
|
387
|
+
prefetchKind: isOptimisticRouteShellPrefetch ? "loading-shell" : "navigation",
|
|
388
|
+
searchAgnosticShell: isAutomaticSearchParamShell && !hasSearchAgnosticShell
|
|
284
389
|
});
|
|
285
390
|
} else if (HAS_PAGES_ROUTER && window.__NEXT_DATA__) {
|
|
286
|
-
const dataTarget = resolvePagesDataNavigationTarget(fullRouteHref, __basePath);
|
|
391
|
+
const dataTarget = resolvePagesDataNavigationTarget(fullRouteHref, __basePath, { locale });
|
|
287
392
|
if (dataTarget) {
|
|
288
393
|
const middlewareDataHref = fullRouteHref === fullHref ? dataTarget.middlewareDataHref : getPagesMiddlewareDataHref(fullHref, __basePath) ?? void 0;
|
|
289
394
|
prefetchPagesData({
|
|
@@ -302,7 +407,12 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref) {
|
|
|
302
407
|
})().catch((error) => {
|
|
303
408
|
console.error("[vinext] RSC prefetch setup error:", error);
|
|
304
409
|
});
|
|
305
|
-
}
|
|
410
|
+
};
|
|
411
|
+
if (priority === "high" || hasAppNavigationRuntime()) {
|
|
412
|
+
runPrefetch();
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
(window.requestIdleCallback ?? ((fn) => setTimeout(fn, 100)))(runPrefetch);
|
|
306
416
|
}
|
|
307
417
|
async function promotePrefetchEntriesForNavigation(href) {
|
|
308
418
|
if (typeof window === "undefined") return;
|
|
@@ -316,6 +426,7 @@ async function promotePrefetchEntriesForNavigation(href) {
|
|
|
316
426
|
}
|
|
317
427
|
for (const [cacheKey, entry] of getPrefetchCache()) {
|
|
318
428
|
if (entry.optimisticRouteShell === true) continue;
|
|
429
|
+
if (entry.prefetchKind === "route-tree") continue;
|
|
319
430
|
const [rscUrl] = cacheKey.split("\0", 1);
|
|
320
431
|
let cached;
|
|
321
432
|
try {
|
|
@@ -334,12 +445,33 @@ async function promotePrefetchEntriesForNavigation(href) {
|
|
|
334
445
|
let sharedObserver = null;
|
|
335
446
|
const observedLinkPrefetches = /* @__PURE__ */ new WeakMap();
|
|
336
447
|
const visibleLinkPrefetches = /* @__PURE__ */ new Set();
|
|
448
|
+
const visibleAppPrefetchQueue = [];
|
|
449
|
+
let visibleAppPrefetchDrainScheduled = false;
|
|
450
|
+
function drainVisibleAppPrefetchQueue() {
|
|
451
|
+
visibleAppPrefetchDrainScheduled = false;
|
|
452
|
+
while (true) {
|
|
453
|
+
const instance = visibleAppPrefetchQueue.pop();
|
|
454
|
+
if (!instance) return;
|
|
455
|
+
instance.queuedViewportPrefetch = false;
|
|
456
|
+
if (!instance.isVisible || instance.routerMode !== "app") continue;
|
|
457
|
+
prefetchUrl(instance.href, instance.mode, "low", instance.pagesRouteHref);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
function scheduleVisibleAppPrefetch(instance) {
|
|
461
|
+
if (instance.queuedViewportPrefetch) return;
|
|
462
|
+
instance.queuedViewportPrefetch = true;
|
|
463
|
+
visibleAppPrefetchQueue.push(instance);
|
|
464
|
+
if (visibleAppPrefetchDrainScheduled) return;
|
|
465
|
+
visibleAppPrefetchDrainScheduled = true;
|
|
466
|
+
queueMicrotask(drainVisibleAppPrefetchQueue);
|
|
467
|
+
}
|
|
337
468
|
function setVisibleLinkPrefetch(instance, isVisible) {
|
|
338
469
|
instance.isVisible = isVisible;
|
|
339
470
|
if (isVisible) {
|
|
340
471
|
visibleLinkPrefetches.add(instance);
|
|
341
472
|
if (instance.routerMode === "pages" && instance.viewportPrefetched) return;
|
|
342
|
-
|
|
473
|
+
if (instance.routerMode === "app") scheduleVisibleAppPrefetch(instance);
|
|
474
|
+
else prefetchUrl(instance.href, instance.mode, "low", instance.pagesRouteHref, instance.locale);
|
|
343
475
|
instance.viewportPrefetched = true;
|
|
344
476
|
} else visibleLinkPrefetches.delete(instance);
|
|
345
477
|
}
|
|
@@ -348,7 +480,7 @@ function registerVisibleLinkPing() {
|
|
|
348
480
|
registerNavigationRuntimeFunctions({ pingVisibleLinks: pingVisibleLinkPrefetches });
|
|
349
481
|
}
|
|
350
482
|
function pingVisibleLinkPrefetches() {
|
|
351
|
-
for (const instance of visibleLinkPrefetches) if (instance.isVisible && instance.routerMode === "app")
|
|
483
|
+
for (const instance of visibleLinkPrefetches) if (instance.isVisible && instance.routerMode === "app") scheduleVisibleAppPrefetch(instance);
|
|
352
484
|
}
|
|
353
485
|
function getSharedObserver() {
|
|
354
486
|
if (typeof window === "undefined" || typeof IntersectionObserver === "undefined") return null;
|
|
@@ -491,12 +623,14 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
|
|
|
491
623
|
const instance = {
|
|
492
624
|
href: hrefToPrefetch,
|
|
493
625
|
isVisible: false,
|
|
626
|
+
locale,
|
|
494
627
|
mode: prefetchMode,
|
|
495
628
|
pagesRouteHref: normalizedRouteHref === normalizedHref ? void 0 : getLinkPrefetchHref({
|
|
496
629
|
href: normalizedRouteHref,
|
|
497
630
|
basePath: __basePath,
|
|
498
631
|
currentOrigin: window.location.origin
|
|
499
632
|
}) ?? void 0,
|
|
633
|
+
queuedViewportPrefetch: false,
|
|
500
634
|
routerMode: getLinkPrefetchRouterMode(),
|
|
501
635
|
viewportPrefetched: false
|
|
502
636
|
};
|
|
@@ -506,12 +640,14 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
|
|
|
506
640
|
observer.unobserve(node);
|
|
507
641
|
observedLinkPrefetches.delete(node);
|
|
508
642
|
visibleLinkPrefetches.delete(instance);
|
|
643
|
+
instance.isVisible = false;
|
|
509
644
|
};
|
|
510
645
|
}, [
|
|
511
646
|
shouldViewportPrefetch,
|
|
512
647
|
prefetchMode,
|
|
513
648
|
normalizedHref,
|
|
514
|
-
normalizedRouteHref
|
|
649
|
+
normalizedRouteHref,
|
|
650
|
+
locale
|
|
515
651
|
]);
|
|
516
652
|
const prefetchOnIntent = useCallback(() => {
|
|
517
653
|
if (!canLinkIntentPrefetch({
|
|
@@ -520,19 +656,20 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
|
|
|
520
656
|
isDangerous,
|
|
521
657
|
routerMode: getLinkPrefetchRouterMode()
|
|
522
658
|
})) return;
|
|
523
|
-
const intentMode = unstable_dynamicOnHover ? "full" : prefetchMode;
|
|
659
|
+
const intentMode = unstable_dynamicOnHover ? "full-after-shell" : prefetchMode;
|
|
524
660
|
if (unstable_dynamicOnHover && internalRef.current) {
|
|
525
661
|
const instance = observedLinkPrefetches.get(internalRef.current);
|
|
526
|
-
if (instance) instance.mode = "full";
|
|
662
|
+
if (instance) instance.mode = "full-after-shell";
|
|
527
663
|
promotePrefetchEntriesForNavigation(normalizedHref);
|
|
528
664
|
}
|
|
529
|
-
prefetchUrl(normalizedHref, intentMode, "high", normalizedRouteHref === normalizedHref ? void 0 : normalizedRouteHref);
|
|
665
|
+
prefetchUrl(normalizedHref, intentMode, "high", normalizedRouteHref === normalizedHref ? void 0 : normalizedRouteHref, locale);
|
|
530
666
|
}, [
|
|
531
667
|
prefetchProp,
|
|
532
668
|
isDangerous,
|
|
533
669
|
prefetchMode,
|
|
534
670
|
normalizedHref,
|
|
535
671
|
normalizedRouteHref,
|
|
672
|
+
locale,
|
|
536
673
|
unstable_dynamicOnHover
|
|
537
674
|
]);
|
|
538
675
|
const handleMouseEnter = useCallback((e) => {
|
|
@@ -10,8 +10,8 @@ import * as React$1 from "react";
|
|
|
10
10
|
//#region src/shims/navigation.d.ts
|
|
11
11
|
/** basePath from next.config.js, injected by the plugin at build time */
|
|
12
12
|
declare const __basePath: string;
|
|
13
|
-
/** Maximum
|
|
14
|
-
declare const MAX_PREFETCH_CACHE_SIZE
|
|
13
|
+
/** Maximum buffered bytes in the RSC prefetch cache. Mirrors Next.js' 50 MB LRU. */
|
|
14
|
+
declare const MAX_PREFETCH_CACHE_SIZE: number;
|
|
15
15
|
declare const DYNAMIC_NAVIGATION_CACHE_TTL: number;
|
|
16
16
|
declare const PREFETCH_CACHE_TTL: number;
|
|
17
17
|
/** A buffered RSC response stored as an ArrayBuffer for replay. */
|
|
@@ -23,12 +23,14 @@ type CachedRscResponse = {
|
|
|
23
23
|
expiresAt?: number;
|
|
24
24
|
mountedSlotsHeader?: string | null;
|
|
25
25
|
paramsHeader: string | null;
|
|
26
|
+
renderedPathAndSearch: string | null;
|
|
26
27
|
url: string;
|
|
27
28
|
};
|
|
28
29
|
type PrefetchOptions = {
|
|
29
30
|
kind?: unknown;
|
|
30
31
|
onInvalidate?: () => void;
|
|
31
32
|
};
|
|
33
|
+
type PrefetchCacheKind = "loading-shell" | "navigation" | "route-tree";
|
|
32
34
|
type PrefetchCacheEntry = {
|
|
33
35
|
cacheForNavigation?: boolean;
|
|
34
36
|
expiresAt?: number;
|
|
@@ -38,7 +40,11 @@ type PrefetchCacheEntry = {
|
|
|
38
40
|
optimisticRouteShell?: boolean;
|
|
39
41
|
outcome: "pending" | "cache-seeded";
|
|
40
42
|
snapshot?: CachedRscResponse;
|
|
43
|
+
cacheKeys?: Set<string>;
|
|
41
44
|
pending?: Promise<void>;
|
|
45
|
+
prefetchKind?: PrefetchCacheKind;
|
|
46
|
+
searchAgnosticShell?: boolean;
|
|
47
|
+
size?: number;
|
|
42
48
|
timestamp: number;
|
|
43
49
|
};
|
|
44
50
|
declare function getCurrentInterceptionContext(): string | null;
|
|
@@ -55,8 +61,10 @@ declare function resolveCachedRscResponseTtlMs(cached: Pick<CachedRscResponse, "
|
|
|
55
61
|
declare function resolveCachedRscResponseExpiresAt(timestamp: number, cached: Pick<CachedRscResponse, "dynamicStaleTimeSeconds" | "expiresAt">, fallbackTtlMs: number): number;
|
|
56
62
|
declare function resolvePrefetchCacheEntryMountedSlotsHeader(entry: PrefetchCacheEntry): string | null;
|
|
57
63
|
declare function hasPrefetchCacheEntryForNavigation(rscUrl: string, interceptionContext?: string | null, mountedSlotsHeader?: string | null, options?: {
|
|
64
|
+
additionalRscUrls?: readonly string[];
|
|
58
65
|
notifyInvalidation?: boolean;
|
|
59
66
|
}): boolean;
|
|
67
|
+
declare function hasSearchAgnosticPrefetchShellForRoute(rscUrl: string, interceptionContext?: string | null, mountedSlotsHeader?: string | null): boolean;
|
|
60
68
|
declare function invalidatePrefetchCache(): void;
|
|
61
69
|
declare function seedPrefetchResponseSnapshot(rscUrl: string, snapshot: CachedRscResponse, interceptionContext?: string | null, mountedSlotsHeader?: string | null, fallbackTtlMs?: number): void;
|
|
62
70
|
declare function deletePrefetchResponseSnapshot(rscUrl: string, snapshot: CachedRscResponse, interceptionContext?: string | null): void;
|
|
@@ -110,7 +118,10 @@ declare function prefetchRscResponse(rscUrl: string, fetchPromise: Promise<Respo
|
|
|
110
118
|
cacheForNavigation?: boolean;
|
|
111
119
|
fallbackTtlMs?: number;
|
|
112
120
|
optimisticRouteShell?: boolean;
|
|
121
|
+
prefetchKind?: PrefetchCacheKind;
|
|
122
|
+
searchAgnosticShell?: boolean;
|
|
113
123
|
}): void;
|
|
124
|
+
declare function peekPrefetchResponseForNavigation(rscUrl: string, interceptionContext?: string | null, mountedSlotsHeader?: string | null): CachedRscResponse | null;
|
|
114
125
|
/**
|
|
115
126
|
* Consume a prefetched response for a given rscUrl.
|
|
116
127
|
* Only returns settled (non-pending) snapshots synchronously.
|
|
@@ -125,6 +136,7 @@ declare function consumePrefetchResponse(rscUrl: string, interceptionContext?: s
|
|
|
125
136
|
* one in-flight network request that navigation should share.
|
|
126
137
|
*/
|
|
127
138
|
type ConsumePrefetchResponseForNavigationOptions = {
|
|
139
|
+
additionalRscUrls?: readonly string[];
|
|
128
140
|
shouldConsume?: () => boolean;
|
|
129
141
|
};
|
|
130
142
|
declare function consumePrefetchResponseForNavigation(rscUrl: string, interceptionContext?: string | null, mountedSlotsHeader?: string | null, options?: ConsumePrefetchResponseForNavigationOptions): Promise<CachedRscResponse | null>;
|
|
@@ -287,4 +299,4 @@ declare function useSelectedLayoutSegments(parallelRoutesKey?: string): string[]
|
|
|
287
299
|
*/
|
|
288
300
|
declare function useServerInsertedHTML(callback: () => unknown): void;
|
|
289
301
|
//#endregion
|
|
290
|
-
export { BailoutToCSRError, CachedRscResponse, ClientNavigationRenderSnapshot, DYNAMIC_NAVIGATION_CACHE_TTL, DynamicServerError, GLOBAL_ACCESSORS_KEY, HTTP_ERROR_FALLBACK_ERROR_CODE, MAX_PREFETCH_CACHE_SIZE, type NavigationContext, type NavigationStateAccessors, PREFETCH_CACHE_TTL, PrefetchCacheEntry, PrefetchOptions, ReadonlyURLSearchParams, RedirectType, type SegmentMap, ServerInsertedHTMLContext, UnrecognizedActionError, __basePath, _registerStateAccessors, activateNavigationSnapshot, appRouterInstance, applyAppRouterScrollFallback, clearPendingPathname, clearServerInsertedHTML, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, decodeRedirectError, deletePrefetchResponseSnapshot, flushServerInsertedHTML, forbidden, getAccessFallbackHTTPStatus, getBfcacheIdMapContext, getBfcacheSegmentIdContext, getClientNavigationRenderContext, getClientNavigationState, getClientParams, getCurrentInterceptionContext, getCurrentNextUrl, getLayoutSegmentContext, getMountedSlotsHeader, getNavigationContext, getPrefetchCache, getPrefetchInterceptionContext, getPrefetchedUrls, hasPrefetchCacheEntryForNavigation, invalidatePrefetchCache, isBailoutToCSRError, isDynamicServerError, isHTTPAccessFallbackError, isNextRouterError, isRedirectError, navigateClientSide, notFound, permanentRedirect, prefetchRscResponse, pushHistoryStateWithoutNotify, redirect, renderServerInsertedHTML, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveCachedRscResponseExpiresAt, resolveCachedRscResponseTtlMs, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setNavigationContext, setPendingPathname, snapshotRscResponse, storePrefetchResponse, unauthorized, unstable_isUnrecognizedActionError, unstable_rethrow, useClientNavigationRenderSnapshot, useParams, usePathname, useRouter, useSearchParams, useSelectedLayoutSegment, useSelectedLayoutSegments, useServerInsertedHTML };
|
|
302
|
+
export { BailoutToCSRError, CachedRscResponse, ClientNavigationRenderSnapshot, DYNAMIC_NAVIGATION_CACHE_TTL, DynamicServerError, GLOBAL_ACCESSORS_KEY, HTTP_ERROR_FALLBACK_ERROR_CODE, MAX_PREFETCH_CACHE_SIZE, type NavigationContext, type NavigationStateAccessors, PREFETCH_CACHE_TTL, PrefetchCacheEntry, PrefetchCacheKind, PrefetchOptions, ReadonlyURLSearchParams, RedirectType, type SegmentMap, ServerInsertedHTMLContext, UnrecognizedActionError, __basePath, _registerStateAccessors, activateNavigationSnapshot, appRouterInstance, applyAppRouterScrollFallback, clearPendingPathname, clearServerInsertedHTML, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, decodeRedirectError, deletePrefetchResponseSnapshot, flushServerInsertedHTML, forbidden, getAccessFallbackHTTPStatus, getBfcacheIdMapContext, getBfcacheSegmentIdContext, getClientNavigationRenderContext, getClientNavigationState, getClientParams, getCurrentInterceptionContext, getCurrentNextUrl, getLayoutSegmentContext, getMountedSlotsHeader, getNavigationContext, getPrefetchCache, getPrefetchInterceptionContext, getPrefetchedUrls, hasPrefetchCacheEntryForNavigation, hasSearchAgnosticPrefetchShellForRoute, invalidatePrefetchCache, isBailoutToCSRError, isDynamicServerError, isHTTPAccessFallbackError, isNextRouterError, isRedirectError, navigateClientSide, notFound, peekPrefetchResponseForNavigation, permanentRedirect, prefetchRscResponse, pushHistoryStateWithoutNotify, redirect, renderServerInsertedHTML, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveCachedRscResponseExpiresAt, resolveCachedRscResponseTtlMs, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setNavigationContext, setPendingPathname, snapshotRscResponse, storePrefetchResponse, unauthorized, unstable_isUnrecognizedActionError, unstable_rethrow, useClientNavigationRenderSnapshot, useParams, usePathname, useRouter, useSearchParams, useSelectedLayoutSegment, useSelectedLayoutSegments, useServerInsertedHTML };
|