vinext 0.0.53 → 0.0.55
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 +1 -0
- package/dist/build/inline-css.d.ts +7 -0
- package/dist/build/inline-css.js +50 -0
- package/dist/build/inline-css.js.map +1 -0
- package/dist/build/prerender.js +2 -1
- package/dist/build/prerender.js.map +1 -1
- package/dist/check.js +19 -3
- package/dist/check.js.map +1 -1
- package/dist/client/navigation-runtime.d.ts +3 -1
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/client/navigation-runtime.js.map +1 -1
- package/dist/client/window-next.d.ts +7 -0
- package/dist/client/window-next.js.map +1 -1
- package/dist/config/next-config.d.ts +97 -2
- package/dist/config/next-config.js +155 -6
- package/dist/config/next-config.js.map +1 -1
- package/dist/config/tsconfig-paths.d.ts +12 -3
- package/dist/config/tsconfig-paths.js +55 -24
- package/dist/config/tsconfig-paths.js.map +1 -1
- package/dist/deploy.js +13 -0
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-browser-entry.d.ts +11 -1
- package/dist/entries/app-browser-entry.js +16 -6
- package/dist/entries/app-browser-entry.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +9 -1
- package/dist/entries/app-rsc-entry.js +30 -5
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.d.ts +21 -1
- package/dist/entries/app-rsc-manifest.js +28 -9
- package/dist/entries/app-rsc-manifest.js.map +1 -1
- package/dist/entries/pages-client-entry.d.ts +4 -1
- package/dist/entries/pages-client-entry.js +18 -2
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +123 -8
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/entries/runtime-entry-module.d.ts +1 -10
- package/dist/entries/runtime-entry-module.js +2 -12
- package/dist/entries/runtime-entry-module.js.map +1 -1
- package/dist/index.js +144 -44
- package/dist/index.js.map +1 -1
- package/dist/plugins/import-meta-url.d.ts +16 -0
- package/dist/plugins/import-meta-url.js +193 -0
- package/dist/plugins/import-meta-url.js.map +1 -0
- package/dist/plugins/remove-console.d.ts +16 -0
- package/dist/plugins/remove-console.js +176 -0
- package/dist/plugins/remove-console.js.map +1 -0
- package/dist/routing/app-route-graph.d.ts +24 -1
- package/dist/routing/app-route-graph.js +52 -4
- package/dist/routing/app-route-graph.js.map +1 -1
- package/dist/routing/app-router.d.ts +2 -2
- package/dist/routing/app-router.js +2 -2
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +21 -1
- package/dist/routing/file-matcher.js +39 -1
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/pages-router.d.ts +1 -1
- package/dist/routing/pages-router.js +10 -3
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/server/api-handler.js +1 -1
- package/dist/server/app-browser-action-result.d.ts +9 -16
- package/dist/server/app-browser-action-result.js +25 -14
- package/dist/server/app-browser-action-result.js.map +1 -1
- package/dist/server/app-browser-entry.js +195 -60
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-mpa-navigation.d.ts +16 -0
- package/dist/server/app-browser-mpa-navigation.js +36 -0
- package/dist/server/app-browser-mpa-navigation.js.map +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +2 -0
- package/dist/server/app-browser-navigation-controller.js +4 -0
- package/dist/server/app-browser-navigation-controller.js.map +1 -1
- package/dist/server/app-browser-popstate.d.ts +3 -1
- package/dist/server/app-browser-popstate.js +15 -1
- package/dist/server/app-browser-popstate.js.map +1 -1
- package/dist/server/app-browser-state.js +2 -1
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-elements-wire.d.ts +13 -4
- package/dist/server/app-elements-wire.js +10 -1
- package/dist/server/app-elements-wire.js.map +1 -1
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-fallback-renderer.d.ts +15 -5
- package/dist/server/app-fallback-renderer.js +10 -4
- package/dist/server/app-fallback-renderer.js.map +1 -1
- package/dist/server/app-inline-css-client.d.ts +7 -0
- package/dist/server/app-inline-css-client.js +37 -0
- package/dist/server/app-inline-css-client.js.map +1 -0
- package/dist/server/app-layout-param-observation.d.ts +30 -0
- package/dist/server/app-layout-param-observation.js +130 -0
- package/dist/server/app-layout-param-observation.js.map +1 -0
- package/dist/server/app-page-boundary-render.js +2 -2
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.d.ts +21 -1
- package/dist/server/app-page-boundary.js +28 -3
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +7 -3
- package/dist/server/app-page-cache.js +7 -7
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +10 -1
- package/dist/server/app-page-dispatch.js +126 -79
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.js +12 -28
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-params.d.ts +2 -1
- package/dist/server/app-page-params.js +14 -1
- package/dist/server/app-page-params.js.map +1 -1
- package/dist/server/app-page-probe.d.ts +12 -1
- package/dist/server/app-page-probe.js +116 -1
- package/dist/server/app-page-probe.js.map +1 -1
- package/dist/server/app-page-render-identity.d.ts +22 -0
- package/dist/server/app-page-render-identity.js +42 -0
- package/dist/server/app-page-render-identity.js.map +1 -0
- package/dist/server/app-page-render.d.ts +8 -1
- package/dist/server/app-page-render.js +4 -1
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +6 -3
- package/dist/server/app-page-request.js +5 -2
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.js +2 -2
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +15 -0
- package/dist/server/app-page-route-wiring.js +7 -5
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +11 -0
- package/dist/server/app-page-stream.js +1 -0
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-route-handler-response.js +37 -5
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +3 -2
- package/dist/server/app-rsc-cache-busting.js +9 -7
- package/dist/server/app-rsc-cache-busting.js.map +1 -1
- package/dist/server/app-rsc-handler.d.ts +14 -3
- package/dist/server/app-rsc-handler.js +56 -6
- package/dist/server/app-rsc-handler.js.map +1 -1
- package/dist/server/app-rsc-request-normalization.d.ts +2 -1
- package/dist/server/app-rsc-request-normalization.js +3 -2
- package/dist/server/app-rsc-request-normalization.js.map +1 -1
- package/dist/server/app-segment-config.d.ts +1 -1
- package/dist/server/app-segment-config.js +4 -1
- package/dist/server/app-segment-config.js.map +1 -1
- package/dist/server/app-server-action-execution.d.ts +26 -3
- package/dist/server/app-server-action-execution.js +240 -29
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +22 -7
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-error-meta.js +3 -3
- package/dist/server/app-ssr-error-meta.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +2 -1
- package/dist/server/app-ssr-stream.js +176 -31
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/artifact-compatibility.d.ts +2 -1
- package/dist/server/artifact-compatibility.js +10 -1
- package/dist/server/artifact-compatibility.js.map +1 -1
- package/dist/server/client-reuse-manifest.d.ts +9 -4
- package/dist/server/client-reuse-manifest.js +2 -1
- package/dist/server/client-reuse-manifest.js.map +1 -1
- package/dist/server/client-trace-metadata.d.ts +31 -0
- package/dist/server/client-trace-metadata.js +83 -0
- package/dist/server/client-trace-metadata.js.map +1 -0
- package/dist/server/cookie-utils.d.ts +13 -0
- package/dist/server/cookie-utils.js +20 -0
- package/dist/server/cookie-utils.js.map +1 -0
- package/dist/server/dev-server.d.ts +8 -1
- package/dist/server/dev-server.js +83 -12
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/document-initial-head.d.ts +7 -0
- package/dist/server/document-initial-head.js +35 -0
- package/dist/server/document-initial-head.js.map +1 -0
- package/dist/server/html.d.ts +2 -1
- package/dist/server/html.js +6 -1
- package/dist/server/html.js.map +1 -1
- package/dist/server/isr-cache.d.ts +7 -5
- package/dist/server/isr-cache.js +17 -6
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/middleware-runtime.js +1 -2
- package/dist/server/middleware-runtime.js.map +1 -1
- package/dist/server/pages-document-initial-props.d.ts +89 -0
- package/dist/server/pages-document-initial-props.js +140 -0
- package/dist/server/pages-document-initial-props.js.map +1 -0
- package/dist/server/pages-node-compat.js +1 -1
- package/dist/server/pages-page-data.js +3 -0
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-method.d.ts +48 -0
- package/dist/server/pages-page-method.js +19 -0
- package/dist/server/pages-page-method.js.map +1 -0
- package/dist/server/pages-page-response.d.ts +20 -0
- package/dist/server/pages-page-response.js +37 -7
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/pages-serializable-props.d.ts +25 -0
- package/dist/server/pages-serializable-props.js +69 -0
- package/dist/server/pages-serializable-props.js.map +1 -0
- package/dist/server/prod-server.js +16 -6
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/server-action-not-found.js +3 -2
- package/dist/server/server-action-not-found.js.map +1 -1
- package/dist/server/skip-cache-proof.d.ts +23 -2
- package/dist/server/skip-cache-proof.js +81 -12
- package/dist/server/skip-cache-proof.js.map +1 -1
- package/dist/server/static-file-cache.js +2 -1
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/server/static-layout-client-reuse-proof.d.ts +16 -0
- package/dist/server/static-layout-client-reuse-proof.js +35 -0
- package/dist/server/static-layout-client-reuse-proof.js.map +1 -0
- package/dist/shims/app-router-scroll-state.d.ts +4 -2
- package/dist/shims/app-router-scroll-state.js +16 -3
- package/dist/shims/app-router-scroll-state.js.map +1 -1
- package/dist/shims/app-router-scroll.d.ts +16 -2
- package/dist/shims/app-router-scroll.js +18 -3
- package/dist/shims/app-router-scroll.js.map +1 -1
- package/dist/shims/cache.d.ts +27 -1
- package/dist/shims/cache.js +108 -6
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/document.d.ts +6 -0
- package/dist/shims/document.js +7 -8
- package/dist/shims/document.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +4 -4
- package/dist/shims/error-boundary.js +27 -28
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/error.js +3 -0
- package/dist/shims/error.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +16 -5
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/hash-scroll.d.ts +4 -1
- package/dist/shims/hash-scroll.js +13 -1
- package/dist/shims/hash-scroll.js.map +1 -1
- package/dist/shims/head-state.d.ts +1 -0
- package/dist/shims/head-state.js +18 -3
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/head.d.ts +35 -1
- package/dist/shims/head.js +113 -14
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +7 -0
- package/dist/shims/headers.js +9 -1
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/internal/app-route-detection.d.ts +37 -0
- package/dist/shims/internal/app-route-detection.js +69 -0
- package/dist/shims/internal/app-route-detection.js.map +1 -0
- package/dist/shims/internal/pages-data-fetch-dedup.d.ts +56 -0
- package/dist/shims/internal/pages-data-fetch-dedup.js +70 -0
- package/dist/shims/internal/pages-data-fetch-dedup.js.map +1 -0
- package/dist/shims/link.d.ts +18 -2
- package/dist/shims/link.js +98 -8
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +7 -6
- package/dist/shims/metadata.js +9 -5
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +40 -3
- package/dist/shims/navigation.js +124 -25
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/router.d.ts +5 -0
- package/dist/shims/router.js +51 -21
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.d.ts +11 -1
- package/dist/shims/script.js +75 -6
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/thenable-params.d.ts +5 -2
- package/dist/shims/thenable-params.js +25 -1
- package/dist/shims/thenable-params.js.map +1 -1
- package/dist/shims/unified-request-context.js +3 -0
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/utils/client-build-manifest.d.ts +15 -0
- package/dist/utils/client-build-manifest.js +54 -0
- package/dist/utils/client-build-manifest.js.map +1 -0
- package/dist/utils/hash.js +1 -1
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/lazy-chunks.d.ts +1 -1
- package/dist/utils/lazy-chunks.js.map +1 -1
- package/dist/utils/path.d.ts +13 -0
- package/dist/utils/path.js +16 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/vite-version.d.ts +11 -0
- package/dist/utils/vite-version.js +36 -0
- package/dist/utils/vite-version.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { VinextLinkPrefetchRoute } from "../../client/vinext-next-data.js";
|
|
2
|
+
|
|
3
|
+
//#region src/shims/internal/app-route-detection.d.ts
|
|
4
|
+
declare global {
|
|
5
|
+
interface Window {
|
|
6
|
+
__VINEXT_LINK_PREFETCH_ROUTES__?: VinextLinkPrefetchRoute[];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Pages Router `components` map shape. Next.js types this loosely (route
|
|
11
|
+
* pattern → `PrivateRouteInfo`), but for the App Router-detected case it
|
|
12
|
+
* stores `{ __appRouter: true }` as a marker (see Next.js source link above).
|
|
13
|
+
* Vinext only writes the marker variant; reads are by test code that checks
|
|
14
|
+
* for `__appRouter: true`.
|
|
15
|
+
*/
|
|
16
|
+
type PagesRouterComponentsMap = Record<string, {
|
|
17
|
+
__appRouter: true;
|
|
18
|
+
} | Record<string, unknown>>;
|
|
19
|
+
/**
|
|
20
|
+
* Get-or-create the Pages Router `components` map. Returns the same object
|
|
21
|
+
* on every call so `router.components` and `window.next.router.components`
|
|
22
|
+
* have referential identity.
|
|
23
|
+
*/
|
|
24
|
+
declare function getPagesRouterComponentsMap(): PagesRouterComponentsMap;
|
|
25
|
+
/**
|
|
26
|
+
* Record `components[pathname] = { __appRouter: true }` on the shared
|
|
27
|
+
* Pages Router map when the href matches an App Router route. No-op when the
|
|
28
|
+
* manifest is absent, the URL is external, or no app route matches.
|
|
29
|
+
*
|
|
30
|
+
* `pathname` is the basePath-stripped path — matching Next.js's
|
|
31
|
+
* `router.components[urlPathname]` key (see the source link in this file's
|
|
32
|
+
* leading comment).
|
|
33
|
+
*/
|
|
34
|
+
declare function markAppRouteDetectedOnPrefetch(href: string, basePath: string): void;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { getPagesRouterComponentsMap, markAppRouteDetectedOnPrefetch };
|
|
37
|
+
//# sourceMappingURL=app-route-detection.d.ts.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { stripBasePath } from "../../utils/base-path.js";
|
|
2
|
+
import { createRouteTrieCache, matchRouteWithTrie } from "../../routing/route-matching.js";
|
|
3
|
+
//#region src/shims/internal/app-route-detection.ts
|
|
4
|
+
const appRouteTrieCache = createRouteTrieCache();
|
|
5
|
+
const _COMPONENTS_KEY = Symbol.for("vinext.pagesRouter.components");
|
|
6
|
+
/**
|
|
7
|
+
* Get-or-create the Pages Router `components` map. Returns the same object
|
|
8
|
+
* on every call so `router.components` and `window.next.router.components`
|
|
9
|
+
* have referential identity.
|
|
10
|
+
*/
|
|
11
|
+
function getPagesRouterComponentsMap() {
|
|
12
|
+
const globalState = globalThis;
|
|
13
|
+
let components = globalState[_COMPONENTS_KEY];
|
|
14
|
+
if (!components) {
|
|
15
|
+
components = {};
|
|
16
|
+
globalState[_COMPONENTS_KEY] = components;
|
|
17
|
+
}
|
|
18
|
+
return components;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a prefetch href to a same-origin pathname (basePath-stripped),
|
|
22
|
+
* suitable as the key used by Next.js for `router.components[urlPathname]`.
|
|
23
|
+
*
|
|
24
|
+
* Returns null for external URLs, malformed URLs, or non-browser contexts.
|
|
25
|
+
*/
|
|
26
|
+
function resolveSameOriginPathname(href, basePath) {
|
|
27
|
+
if (typeof window === "undefined") return null;
|
|
28
|
+
let url;
|
|
29
|
+
try {
|
|
30
|
+
url = new URL(href, window.location.href);
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (url.origin !== window.location.origin) return null;
|
|
35
|
+
return stripBasePath(url.pathname, basePath);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns true when the prefetch href matches any route in the App Router
|
|
39
|
+
* prefetch manifest (static or dynamic). Returns false when the manifest is
|
|
40
|
+
* absent (Pages-Router-only build), the URL is external, or no route matches.
|
|
41
|
+
*/
|
|
42
|
+
function matchesAppRoute(href, basePath) {
|
|
43
|
+
if (typeof window === "undefined") return false;
|
|
44
|
+
const routes = window.__VINEXT_LINK_PREFETCH_ROUTES__;
|
|
45
|
+
if (!routes || routes.length === 0) return false;
|
|
46
|
+
const pathname = resolveSameOriginPathname(href, basePath);
|
|
47
|
+
if (pathname === null) return false;
|
|
48
|
+
return matchRouteWithTrie(pathname, routes, appRouteTrieCache) !== null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Record `components[pathname] = { __appRouter: true }` on the shared
|
|
52
|
+
* Pages Router map when the href matches an App Router route. No-op when the
|
|
53
|
+
* manifest is absent, the URL is external, or no app route matches.
|
|
54
|
+
*
|
|
55
|
+
* `pathname` is the basePath-stripped path — matching Next.js's
|
|
56
|
+
* `router.components[urlPathname]` key (see the source link in this file's
|
|
57
|
+
* leading comment).
|
|
58
|
+
*/
|
|
59
|
+
function markAppRouteDetectedOnPrefetch(href, basePath) {
|
|
60
|
+
if (typeof window === "undefined") return;
|
|
61
|
+
if (!matchesAppRoute(href, basePath)) return;
|
|
62
|
+
const pathname = resolveSameOriginPathname(href, basePath);
|
|
63
|
+
if (pathname === null) return;
|
|
64
|
+
getPagesRouterComponentsMap()[pathname] = { __appRouter: true };
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { getPagesRouterComponentsMap, markAppRouteDetectedOnPrefetch };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=app-route-detection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-route-detection.js","names":[],"sources":["../../../src/shims/internal/app-route-detection.ts"],"sourcesContent":["/**\n * Shared helper for marking an App Router route as \"detected\" on the Pages\n * Router singleton when a `<Link>` or `Router.prefetch` targets it.\n *\n * Ported from Next.js: `packages/next/src/shared/lib/router/router.ts:2525`\n *\n * if (await this._bfl(asPath, resolvedAs, options.locale, true)) {\n * this.components[urlPathname] = { __appRouter: true } as any\n * }\n *\n * Next.js uses a bloom filter (`_bfl`) of App Router routes that the Pages\n * Router cannot handle. When the prefetch target matches the filter, the\n * Pages Router records the route on `this.components` with\n * `{ __appRouter: true }`. The Next.js deploy test\n * test/e2e/app-dir/app/index.test.ts → \"should successfully detect app\n * route during prefetch\"\n * reads this through `window.next.router.components[\"/dashboard\"]`.\n *\n * Vinext does not need a bloom filter — the App Router prefetch route\n * manifest (`__VINEXT_LINK_PREFETCH_ROUTES__`) already lives on the client\n * for Link's App Router auto-prefetch decisions. This helper reuses that\n * manifest and the shared trie matcher to decide whether a prefetch target\n * is an App Router route.\n *\n * Lives in `shims/internal/` so both the Pages Router (`router.ts`) and the\n * Link shim's Pages-mode branch (`link.tsx`) can call it without pulling in\n * the other shim at module init.\n *\n * The components map is stored behind a `Symbol.for` global so the Pages\n * Router (`router.ts`) and the Link shim (`link.tsx`) both write through the\n * same instance even when Vite loads the router shim through a different\n * resolved module ID than the link shim (mirrors the same module-split\n * mitigation used by `navigation.ts`'s GLOBAL_ACCESSORS_KEY).\n *\n * Issue: https://github.com/cloudflare/vinext/issues/1526\n */\nimport type { VinextLinkPrefetchRoute } from \"../../client/vinext-next-data.js\";\nimport { createRouteTrieCache, matchRouteWithTrie } from \"../../routing/route-matching.js\";\nimport { stripBasePath } from \"../../utils/base-path.js\";\n\nconst appRouteTrieCache = createRouteTrieCache<VinextLinkPrefetchRoute>();\n\ndeclare global {\n // oxlint-disable-next-line typescript-eslint/consistent-type-definitions\n interface Window {\n __VINEXT_LINK_PREFETCH_ROUTES__?: VinextLinkPrefetchRoute[];\n }\n}\n\n/**\n * Pages Router `components` map shape. Next.js types this loosely (route\n * pattern → `PrivateRouteInfo`), but for the App Router-detected case it\n * stores `{ __appRouter: true }` as a marker (see Next.js source link above).\n * Vinext only writes the marker variant; reads are by test code that checks\n * for `__appRouter: true`.\n */\ntype PagesRouterComponentsMap = Record<string, { __appRouter: true } | Record<string, unknown>>;\n\nconst _COMPONENTS_KEY = Symbol.for(\"vinext.pagesRouter.components\");\ntype _GlobalWithComponents = typeof globalThis & {\n [_COMPONENTS_KEY]?: PagesRouterComponentsMap;\n};\n\n/**\n * Get-or-create the Pages Router `components` map. Returns the same object\n * on every call so `router.components` and `window.next.router.components`\n * have referential identity.\n */\nexport function getPagesRouterComponentsMap(): PagesRouterComponentsMap {\n const globalState = globalThis as _GlobalWithComponents;\n let components = globalState[_COMPONENTS_KEY];\n if (!components) {\n components = {};\n globalState[_COMPONENTS_KEY] = components;\n }\n return components;\n}\n\n/**\n * Resolve a prefetch href to a same-origin pathname (basePath-stripped),\n * suitable as the key used by Next.js for `router.components[urlPathname]`.\n *\n * Returns null for external URLs, malformed URLs, or non-browser contexts.\n */\nfunction resolveSameOriginPathname(href: string, basePath: string): string | null {\n if (typeof window === \"undefined\") return null;\n let url: URL;\n try {\n url = new URL(href, window.location.href);\n } catch {\n return null;\n }\n if (url.origin !== window.location.origin) return null;\n return stripBasePath(url.pathname, basePath);\n}\n\n/**\n * Returns true when the prefetch href matches any route in the App Router\n * prefetch manifest (static or dynamic). Returns false when the manifest is\n * absent (Pages-Router-only build), the URL is external, or no route matches.\n */\nfunction matchesAppRoute(href: string, basePath: string): boolean {\n if (typeof window === \"undefined\") return false;\n const routes = window.__VINEXT_LINK_PREFETCH_ROUTES__;\n if (!routes || routes.length === 0) return false;\n\n const pathname = resolveSameOriginPathname(href, basePath);\n if (pathname === null) return false;\n\n return matchRouteWithTrie(pathname, routes, appRouteTrieCache) !== null;\n}\n\n/**\n * Record `components[pathname] = { __appRouter: true }` on the shared\n * Pages Router map when the href matches an App Router route. No-op when the\n * manifest is absent, the URL is external, or no app route matches.\n *\n * `pathname` is the basePath-stripped path — matching Next.js's\n * `router.components[urlPathname]` key (see the source link in this file's\n * leading comment).\n */\nexport function markAppRouteDetectedOnPrefetch(href: string, basePath: string): void {\n if (typeof window === \"undefined\") return;\n if (!matchesAppRoute(href, basePath)) return;\n\n const pathname = resolveSameOriginPathname(href, basePath);\n if (pathname === null) return;\n\n getPagesRouterComponentsMap()[pathname] = { __appRouter: true };\n}\n"],"mappings":";;;AAwCA,MAAM,oBAAoB,sBAA+C;AAkBzE,MAAM,kBAAkB,OAAO,IAAI,gCAAgC;;;;;;AAUnE,SAAgB,8BAAwD;CACtE,MAAM,cAAc;CACpB,IAAI,aAAa,YAAY;CAC7B,IAAI,CAAC,YAAY;EACf,aAAa,EAAE;EACf,YAAY,mBAAmB;;CAEjC,OAAO;;;;;;;;AAST,SAAS,0BAA0B,MAAc,UAAiC;CAChF,IAAI,OAAO,WAAW,aAAa,OAAO;CAC1C,IAAI;CACJ,IAAI;EACF,MAAM,IAAI,IAAI,MAAM,OAAO,SAAS,KAAK;SACnC;EACN,OAAO;;CAET,IAAI,IAAI,WAAW,OAAO,SAAS,QAAQ,OAAO;CAClD,OAAO,cAAc,IAAI,UAAU,SAAS;;;;;;;AAQ9C,SAAS,gBAAgB,MAAc,UAA2B;CAChE,IAAI,OAAO,WAAW,aAAa,OAAO;CAC1C,MAAM,SAAS,OAAO;CACtB,IAAI,CAAC,UAAU,OAAO,WAAW,GAAG,OAAO;CAE3C,MAAM,WAAW,0BAA0B,MAAM,SAAS;CAC1D,IAAI,aAAa,MAAM,OAAO;CAE9B,OAAO,mBAAmB,UAAU,QAAQ,kBAAkB,KAAK;;;;;;;;;;;AAYrE,SAAgB,+BAA+B,MAAc,UAAwB;CACnF,IAAI,OAAO,WAAW,aAAa;CACnC,IAAI,CAAC,gBAAgB,MAAM,SAAS,EAAE;CAEtC,MAAM,WAAW,0BAA0B,MAAM,SAAS;CAC1D,IAAI,aAAa,MAAM;CAEvB,6BAA6B,CAAC,YAAY,EAAE,aAAa,MAAM"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//#region src/shims/internal/pages-data-fetch-dedup.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* In-flight request dedup for the Pages Router `/_next/data/<id>/<page>.json`
|
|
4
|
+
* endpoint.
|
|
5
|
+
*
|
|
6
|
+
* Why this exists: when a user (or app code) triggers several near-simultaneous
|
|
7
|
+
* navigations to the same gSSP route — e.g. clicking the same `<Link>` multiple
|
|
8
|
+
* times before the first navigation lands — each call to `Router.push` would
|
|
9
|
+
* otherwise enter its own `navigateClientData()` flow and dispatch its own
|
|
10
|
+
* `fetch()` against the data endpoint. That balloons server load and breaks
|
|
11
|
+
* Next.js' documented "one fetch per unique data URL" guarantee.
|
|
12
|
+
*
|
|
13
|
+
* Ported from Next.js: `fetchNextData()` in
|
|
14
|
+
* `packages/next/src/shared/lib/router/router.ts`. Next.js maintains an
|
|
15
|
+
* `inflightCache` (keyed by the resolved data URL) and reuses the existing
|
|
16
|
+
* Promise when a concurrent caller asks for the same URL. The entry is
|
|
17
|
+
* dropped once the fetch settles (success or rejection) so the next
|
|
18
|
+
* navigation re-fetches fresh.
|
|
19
|
+
*
|
|
20
|
+
* Design notes:
|
|
21
|
+
*
|
|
22
|
+
* - Callers receive a cloned Response, so each can independently consume the
|
|
23
|
+
* body (`.json()`, `.text()`, etc.). The originating Response is never read
|
|
24
|
+
* directly by anyone, which keeps subsequent clones legal even after one
|
|
25
|
+
* caller has consumed its copy.
|
|
26
|
+
*
|
|
27
|
+
* - No `AbortSignal` is honored at the shared layer. Each `Router.push` cycle
|
|
28
|
+
* has its own AbortController that supersedes prior navigations via
|
|
29
|
+
* `_navigationId`; aborting the shared fetch on behalf of one caller would
|
|
30
|
+
* destroy the dedup gain for every other concurrent caller. Cancellation is
|
|
31
|
+
* handled by the caller's `assertStillCurrent()` checkpoints after `await`,
|
|
32
|
+
* not by abort propagation.
|
|
33
|
+
*
|
|
34
|
+
* - The map is module-scoped (one per realm). The Pages Router runs in the
|
|
35
|
+
* browser only, so a single `Map` is sufficient.
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* Dedupe a `fetch()` against the `_next/data` endpoint. Multiple concurrent
|
|
39
|
+
* callers for the same `dataHref` share one underlying network request.
|
|
40
|
+
*
|
|
41
|
+
* Each call returns a freshly-cloned `Response` so consumers can read the
|
|
42
|
+
* body independently. Once the in-flight Promise settles (resolve or reject)
|
|
43
|
+
* the entry is removed, and the next call will hit the network again.
|
|
44
|
+
*
|
|
45
|
+
* Errors propagate to every concurrent caller — the in-flight entry is
|
|
46
|
+
* dropped on failure so the next navigation can retry.
|
|
47
|
+
*/
|
|
48
|
+
declare function dedupedPagesDataFetch(dataHref: string, init?: RequestInit): Promise<Response>;
|
|
49
|
+
/**
|
|
50
|
+
* Drop every cached in-flight entry. Intended for tests; production code
|
|
51
|
+
* does not need to call this because entries self-evict on settle.
|
|
52
|
+
*/
|
|
53
|
+
declare function clearPagesDataInflight(): void;
|
|
54
|
+
//#endregion
|
|
55
|
+
export { clearPagesDataInflight, dedupedPagesDataFetch };
|
|
56
|
+
//# sourceMappingURL=pages-data-fetch-dedup.d.ts.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//#region src/shims/internal/pages-data-fetch-dedup.ts
|
|
2
|
+
/**
|
|
3
|
+
* In-flight request dedup for the Pages Router `/_next/data/<id>/<page>.json`
|
|
4
|
+
* endpoint.
|
|
5
|
+
*
|
|
6
|
+
* Why this exists: when a user (or app code) triggers several near-simultaneous
|
|
7
|
+
* navigations to the same gSSP route — e.g. clicking the same `<Link>` multiple
|
|
8
|
+
* times before the first navigation lands — each call to `Router.push` would
|
|
9
|
+
* otherwise enter its own `navigateClientData()` flow and dispatch its own
|
|
10
|
+
* `fetch()` against the data endpoint. That balloons server load and breaks
|
|
11
|
+
* Next.js' documented "one fetch per unique data URL" guarantee.
|
|
12
|
+
*
|
|
13
|
+
* Ported from Next.js: `fetchNextData()` in
|
|
14
|
+
* `packages/next/src/shared/lib/router/router.ts`. Next.js maintains an
|
|
15
|
+
* `inflightCache` (keyed by the resolved data URL) and reuses the existing
|
|
16
|
+
* Promise when a concurrent caller asks for the same URL. The entry is
|
|
17
|
+
* dropped once the fetch settles (success or rejection) so the next
|
|
18
|
+
* navigation re-fetches fresh.
|
|
19
|
+
*
|
|
20
|
+
* Design notes:
|
|
21
|
+
*
|
|
22
|
+
* - Callers receive a cloned Response, so each can independently consume the
|
|
23
|
+
* body (`.json()`, `.text()`, etc.). The originating Response is never read
|
|
24
|
+
* directly by anyone, which keeps subsequent clones legal even after one
|
|
25
|
+
* caller has consumed its copy.
|
|
26
|
+
*
|
|
27
|
+
* - No `AbortSignal` is honored at the shared layer. Each `Router.push` cycle
|
|
28
|
+
* has its own AbortController that supersedes prior navigations via
|
|
29
|
+
* `_navigationId`; aborting the shared fetch on behalf of one caller would
|
|
30
|
+
* destroy the dedup gain for every other concurrent caller. Cancellation is
|
|
31
|
+
* handled by the caller's `assertStillCurrent()` checkpoints after `await`,
|
|
32
|
+
* not by abort propagation.
|
|
33
|
+
*
|
|
34
|
+
* - The map is module-scoped (one per realm). The Pages Router runs in the
|
|
35
|
+
* browser only, so a single `Map` is sufficient.
|
|
36
|
+
*/
|
|
37
|
+
/** Inflight fetch promises keyed by the resolved data URL. */
|
|
38
|
+
const inflight = /* @__PURE__ */ new Map();
|
|
39
|
+
/**
|
|
40
|
+
* Dedupe a `fetch()` against the `_next/data` endpoint. Multiple concurrent
|
|
41
|
+
* callers for the same `dataHref` share one underlying network request.
|
|
42
|
+
*
|
|
43
|
+
* Each call returns a freshly-cloned `Response` so consumers can read the
|
|
44
|
+
* body independently. Once the in-flight Promise settles (resolve or reject)
|
|
45
|
+
* the entry is removed, and the next call will hit the network again.
|
|
46
|
+
*
|
|
47
|
+
* Errors propagate to every concurrent caller — the in-flight entry is
|
|
48
|
+
* dropped on failure so the next navigation can retry.
|
|
49
|
+
*/
|
|
50
|
+
function dedupedPagesDataFetch(dataHref, init) {
|
|
51
|
+
let entry = inflight.get(dataHref);
|
|
52
|
+
if (!entry) {
|
|
53
|
+
entry = fetch(dataHref, init).finally(() => {
|
|
54
|
+
if (inflight.get(dataHref) === entry) inflight.delete(dataHref);
|
|
55
|
+
});
|
|
56
|
+
inflight.set(dataHref, entry);
|
|
57
|
+
}
|
|
58
|
+
return entry.then((res) => res.clone());
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Drop every cached in-flight entry. Intended for tests; production code
|
|
62
|
+
* does not need to call this because entries self-evict on settle.
|
|
63
|
+
*/
|
|
64
|
+
function clearPagesDataInflight() {
|
|
65
|
+
inflight.clear();
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { clearPagesDataInflight, dedupedPagesDataFetch };
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=pages-data-fetch-dedup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pages-data-fetch-dedup.js","names":[],"sources":["../../../src/shims/internal/pages-data-fetch-dedup.ts"],"sourcesContent":["/**\n * In-flight request dedup for the Pages Router `/_next/data/<id>/<page>.json`\n * endpoint.\n *\n * Why this exists: when a user (or app code) triggers several near-simultaneous\n * navigations to the same gSSP route — e.g. clicking the same `<Link>` multiple\n * times before the first navigation lands — each call to `Router.push` would\n * otherwise enter its own `navigateClientData()` flow and dispatch its own\n * `fetch()` against the data endpoint. That balloons server load and breaks\n * Next.js' documented \"one fetch per unique data URL\" guarantee.\n *\n * Ported from Next.js: `fetchNextData()` in\n * `packages/next/src/shared/lib/router/router.ts`. Next.js maintains an\n * `inflightCache` (keyed by the resolved data URL) and reuses the existing\n * Promise when a concurrent caller asks for the same URL. The entry is\n * dropped once the fetch settles (success or rejection) so the next\n * navigation re-fetches fresh.\n *\n * Design notes:\n *\n * - Callers receive a cloned Response, so each can independently consume the\n * body (`.json()`, `.text()`, etc.). The originating Response is never read\n * directly by anyone, which keeps subsequent clones legal even after one\n * caller has consumed its copy.\n *\n * - No `AbortSignal` is honored at the shared layer. Each `Router.push` cycle\n * has its own AbortController that supersedes prior navigations via\n * `_navigationId`; aborting the shared fetch on behalf of one caller would\n * destroy the dedup gain for every other concurrent caller. Cancellation is\n * handled by the caller's `assertStillCurrent()` checkpoints after `await`,\n * not by abort propagation.\n *\n * - The map is module-scoped (one per realm). The Pages Router runs in the\n * browser only, so a single `Map` is sufficient.\n */\n\n/** Inflight fetch promises keyed by the resolved data URL. */\nconst inflight = new Map<string, Promise<Response>>();\n\n/**\n * Dedupe a `fetch()` against the `_next/data` endpoint. Multiple concurrent\n * callers for the same `dataHref` share one underlying network request.\n *\n * Each call returns a freshly-cloned `Response` so consumers can read the\n * body independently. Once the in-flight Promise settles (resolve or reject)\n * the entry is removed, and the next call will hit the network again.\n *\n * Errors propagate to every concurrent caller — the in-flight entry is\n * dropped on failure so the next navigation can retry.\n */\nexport function dedupedPagesDataFetch(dataHref: string, init?: RequestInit): Promise<Response> {\n let entry = inflight.get(dataHref);\n if (!entry) {\n entry = fetch(dataHref, init).finally(() => {\n // Only drop the entry if it still matches the one we set. A racing\n // caller could in principle overwrite, but inflight is keyed by URL\n // and we never overwrite on a hit, so this check is defensive.\n if (inflight.get(dataHref) === entry) inflight.delete(dataHref);\n });\n inflight.set(dataHref, entry);\n }\n // Always return a clone so each consumer gets an independently-readable\n // body. The original `entry` Response is never consumed directly, so\n // cloning remains valid for every caller (including the first).\n return entry.then((res) => res.clone());\n}\n\n/**\n * Drop every cached in-flight entry. Intended for tests; production code\n * does not need to call this because entries self-evict on settle.\n */\nexport function clearPagesDataInflight(): void {\n inflight.clear();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,MAAM,2BAAW,IAAI,KAAgC;;;;;;;;;;;;AAarD,SAAgB,sBAAsB,UAAkB,MAAuC;CAC7F,IAAI,QAAQ,SAAS,IAAI,SAAS;CAClC,IAAI,CAAC,OAAO;EACV,QAAQ,MAAM,UAAU,KAAK,CAAC,cAAc;GAI1C,IAAI,SAAS,IAAI,SAAS,KAAK,OAAO,SAAS,OAAO,SAAS;IAC/D;EACF,SAAS,IAAI,UAAU,MAAM;;CAK/B,OAAO,MAAM,MAAM,QAAQ,IAAI,OAAO,CAAC;;;;;;AAOzC,SAAgB,yBAA+B;CAC7C,SAAS,OAAO"}
|
package/dist/shims/link.d.ts
CHANGED
|
@@ -21,7 +21,15 @@ type LinkProps = {
|
|
|
21
21
|
* is upgraded to a full prefetch when the user shows navigation intent.
|
|
22
22
|
*/
|
|
23
23
|
unstable_dynamicOnHover?: boolean; /** Whether to pass the href to the child element */
|
|
24
|
-
passHref?: boolean;
|
|
24
|
+
passHref?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Pre-Next.js-13 link behaviour. When true, <Link> expects its child to be
|
|
27
|
+
* an `<a>` (or a component that renders one) and forwards `href`, click,
|
|
28
|
+
* and prefetch handlers to the child via `React.cloneElement` instead of
|
|
29
|
+
* rendering its own wrapping `<a>`. Required when the user wants to
|
|
30
|
+
* style/instrument the anchor themselves.
|
|
31
|
+
*/
|
|
32
|
+
legacyBehavior?: boolean; /** Scroll to top on navigation (default: true) */
|
|
25
33
|
scroll?: boolean;
|
|
26
34
|
/**
|
|
27
35
|
* Pages Router: update the URL without re-running data fetching methods
|
|
@@ -68,7 +76,15 @@ declare const Link: React.ForwardRefExoticComponent<{
|
|
|
68
76
|
* is upgraded to a full prefetch when the user shows navigation intent.
|
|
69
77
|
*/
|
|
70
78
|
unstable_dynamicOnHover?: boolean; /** Whether to pass the href to the child element */
|
|
71
|
-
passHref?: boolean;
|
|
79
|
+
passHref?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Pre-Next.js-13 link behaviour. When true, <Link> expects its child to be
|
|
82
|
+
* an `<a>` (or a component that renders one) and forwards `href`, click,
|
|
83
|
+
* and prefetch handlers to the child via `React.cloneElement` instead of
|
|
84
|
+
* rendering its own wrapping `<a>`. Required when the user wants to
|
|
85
|
+
* style/instrument the anchor themselves.
|
|
86
|
+
*/
|
|
87
|
+
legacyBehavior?: boolean; /** Scroll to top on navigation (default: true) */
|
|
72
88
|
scroll?: boolean;
|
|
73
89
|
/**
|
|
74
90
|
* Pages Router: update the URL without re-running data fetching methods
|
package/dist/shims/link.js
CHANGED
|
@@ -3,15 +3,16 @@ import { stripBasePath } from "../utils/base-path.js";
|
|
|
3
3
|
import { createRouteTrieCache, matchRouteWithTrie } from "../routing/route-matching.js";
|
|
4
4
|
import { VINEXT_MOUNTED_SLOTS_HEADER } from "../server/headers.js";
|
|
5
5
|
import { isDangerousScheme, reportBlockedDangerousNavigation } from "./url-safety.js";
|
|
6
|
-
import { appendSearchParamsToUrl, urlQueryToSearchParams } from "../utils/query.js";
|
|
7
6
|
import { AppElementsWire } from "../server/app-elements-wire.js";
|
|
8
7
|
import { APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL } from "../server/app-rsc-render-mode.js";
|
|
8
|
+
import "../server/app-elements.js";
|
|
9
9
|
import { addLocalePrefix, getDomainLocaleUrl } from "../utils/domain-locale.js";
|
|
10
10
|
import { prefetchPagesData, resolvePagesDataNavigationTarget } from "./internal/pages-data-target.js";
|
|
11
|
+
import { markAppRouteDetectedOnPrefetch } from "./internal/app-route-detection.js";
|
|
11
12
|
import { isAbsoluteOrProtocolRelativeUrl, normalizePathTrailingSlash, resolveRelativeHref, toBrowserNavigationHref, toSameOriginAppPath, withBasePath } from "./url-utils.js";
|
|
13
|
+
import { appendSearchParamsToUrl, urlQueryToSearchParams } from "../utils/query.js";
|
|
12
14
|
import { getCurrentBrowserLocale } from "./client-locale.js";
|
|
13
15
|
import { getNavigationRuntime, hasAppNavigationRuntime, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
|
|
14
|
-
import "../server/app-elements.js";
|
|
15
16
|
import { createRscRequestHeaders, createRscRequestUrl, stripRscCacheBustingSearchParam, stripRscSuffix } from "../server/app-rsc-cache-busting.js";
|
|
16
17
|
import { getMountedSlotsHeader, getPrefetchCache, getPrefetchInterceptionContext, getPrefetchedUrls, navigateClientSide, prefetchRscResponse } from "./navigation.js";
|
|
17
18
|
import { navigatePagesRouterLink } from "../client/pages-router-link-navigation.js";
|
|
@@ -40,6 +41,7 @@ function useLinkStatus() {
|
|
|
40
41
|
const __basePath = process.env.__NEXT_ROUTER_BASEPATH ?? "";
|
|
41
42
|
/** trailingSlash from next.config.js, injected by the plugin at build time */
|
|
42
43
|
const __trailingSlash = process.env.__VINEXT_TRAILING_SLASH === "true";
|
|
44
|
+
const __prefetchInlining = process.env.__VINEXT_PREFETCH_INLINING === "true";
|
|
43
45
|
const linkPrefetchRouteTrieCache = createRouteTrieCache();
|
|
44
46
|
function resolveHref(href) {
|
|
45
47
|
if (typeof href === "string") return href;
|
|
@@ -167,7 +169,11 @@ function prefetchUrl(href, mode, priority = "low") {
|
|
|
167
169
|
});
|
|
168
170
|
if (prefetchHref == null) return;
|
|
169
171
|
const fullHref = toBrowserNavigationHref(prefetchHref, window.location.href, __basePath);
|
|
170
|
-
|
|
172
|
+
const target = new URL(fullHref, window.location.href);
|
|
173
|
+
if (target.origin === window.location.origin && target.pathname === window.location.pathname && target.search === window.location.search) return;
|
|
174
|
+
(priority === "high" ? (fn) => {
|
|
175
|
+
fn();
|
|
176
|
+
} : window.requestIdleCallback ?? ((fn) => setTimeout(fn, 100)))(() => {
|
|
171
177
|
(async () => {
|
|
172
178
|
if (hasAppNavigationRuntime()) {
|
|
173
179
|
const autoPrefetch = mode === "auto" ? resolveAutoAppRoutePrefetch(prefetchHref) : {
|
|
@@ -195,7 +201,28 @@ function prefetchUrl(href, mode, priority = "low") {
|
|
|
195
201
|
return;
|
|
196
202
|
}
|
|
197
203
|
prefetched.add(cacheKey);
|
|
198
|
-
prefetchRscResponse(rscUrl,
|
|
204
|
+
prefetchRscResponse(rscUrl, __prefetchInlining && autoPrefetch.cacheForNavigation ? (async () => {
|
|
205
|
+
const shellHeaders = createRscRequestHeaders({
|
|
206
|
+
interceptionContext,
|
|
207
|
+
renderMode: APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL
|
|
208
|
+
});
|
|
209
|
+
if (mountedSlotsHeader) shellHeaders.set(VINEXT_MOUNTED_SLOTS_HEADER, mountedSlotsHeader);
|
|
210
|
+
const shellRscUrl = await createRscRequestUrl(fullHref, shellHeaders);
|
|
211
|
+
const shellResponse = await fetch(shellRscUrl, {
|
|
212
|
+
headers: shellHeaders,
|
|
213
|
+
credentials: "include",
|
|
214
|
+
priority,
|
|
215
|
+
purpose: "prefetch"
|
|
216
|
+
});
|
|
217
|
+
if (!shellResponse.ok) return shellResponse;
|
|
218
|
+
await shellResponse.arrayBuffer().catch(() => {});
|
|
219
|
+
return fetch(rscUrl, {
|
|
220
|
+
headers,
|
|
221
|
+
credentials: "include",
|
|
222
|
+
priority,
|
|
223
|
+
purpose: "prefetch"
|
|
224
|
+
});
|
|
225
|
+
})() : fetch(rscUrl, {
|
|
199
226
|
headers,
|
|
200
227
|
credentials: "include",
|
|
201
228
|
priority,
|
|
@@ -208,6 +235,7 @@ function prefetchUrl(href, mode, priority = "low") {
|
|
|
208
235
|
const dataTarget = resolvePagesDataNavigationTarget(fullHref, __basePath);
|
|
209
236
|
if (dataTarget) prefetchPagesData(dataTarget);
|
|
210
237
|
else {
|
|
238
|
+
markAppRouteDetectedOnPrefetch(fullHref, __basePath);
|
|
211
239
|
const link = document.createElement("link");
|
|
212
240
|
link.rel = "prefetch";
|
|
213
241
|
link.href = fullHref;
|
|
@@ -334,8 +362,10 @@ function applyLocaleToHref(href, locale) {
|
|
|
334
362
|
}
|
|
335
363
|
return addLocalePrefix(href, resolvedLocale, defaultLocale);
|
|
336
364
|
}
|
|
337
|
-
const Link = forwardRef(function Link({ href, as, replace = false, prefetch: prefetchProp, scroll = true, shallow = false, children, onClick, onMouseEnter, onTouchStart, onNavigate, unstable_dynamicOnHover = false, ...rest }, forwardedRef) {
|
|
365
|
+
const Link = forwardRef(function Link({ href, as, replace = false, prefetch: prefetchProp, scroll = true, shallow = false, children: childrenProp, onClick, onMouseEnter, onTouchStart, onNavigate, unstable_dynamicOnHover = false, legacyBehavior = false, passHref = false, ...rest }, forwardedRef) {
|
|
338
366
|
const { locale, ...restWithoutLocale } = rest;
|
|
367
|
+
let children = childrenProp;
|
|
368
|
+
if (legacyBehavior && (typeof childrenProp === "string" || typeof childrenProp === "number")) children = React.createElement("a", null, childrenProp);
|
|
339
369
|
const rawResolvedHref = as ?? resolveHref(href);
|
|
340
370
|
const resolvedHref = typeof rawResolvedHref === "string" ? warnAndNormalizeRepeatedSlashesInHref(rawResolvedHref) : rawResolvedHref;
|
|
341
371
|
const isDangerous = typeof resolvedHref === "string" && isDangerousScheme(resolvedHref);
|
|
@@ -422,8 +452,8 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
|
|
|
422
452
|
onTouchStart?.(e);
|
|
423
453
|
prefetchOnIntent();
|
|
424
454
|
}, [onTouchStart, prefetchOnIntent]);
|
|
425
|
-
const handleClick = async (e) => {
|
|
426
|
-
if (onClick) onClick(e);
|
|
455
|
+
const handleClick = async (e, options = {}) => {
|
|
456
|
+
if (!options.skipLinkOnClick && onClick) onClick(e);
|
|
427
457
|
if (e.defaultPrevented) return;
|
|
428
458
|
if (e.currentTarget.hasAttribute("download")) return;
|
|
429
459
|
if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
@@ -481,7 +511,7 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
|
|
|
481
511
|
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
482
512
|
}
|
|
483
513
|
};
|
|
484
|
-
const
|
|
514
|
+
const anchorProps = restWithoutLocale;
|
|
485
515
|
const linkStatusValue = React.useMemo(() => ({ pending }), [pending]);
|
|
486
516
|
if (isDangerous) {
|
|
487
517
|
if (process.env.NODE_ENV !== "production") console.warn(`<Link> blocked dangerous href: ${resolvedHref}`);
|
|
@@ -489,6 +519,26 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
|
|
|
489
519
|
if (onClick) onClick(event);
|
|
490
520
|
reportBlockedDangerousNavigation();
|
|
491
521
|
};
|
|
522
|
+
if (legacyBehavior) {
|
|
523
|
+
const child = React.Children.only(children);
|
|
524
|
+
const childOnClick = child.props.onClick;
|
|
525
|
+
const childRef = child.props.ref;
|
|
526
|
+
const setDangerousRefs = (node) => {
|
|
527
|
+
internalRef.current = node;
|
|
528
|
+
if (typeof childRef === "function") childRef(node);
|
|
529
|
+
else if (childRef) childRef.current = node;
|
|
530
|
+
};
|
|
531
|
+
return /* @__PURE__ */ jsx(LinkStatusContext.Provider, {
|
|
532
|
+
value: linkStatusValue,
|
|
533
|
+
children: React.cloneElement(child, {
|
|
534
|
+
ref: setDangerousRefs,
|
|
535
|
+
onClick: (event) => {
|
|
536
|
+
if (childOnClick) childOnClick(event);
|
|
537
|
+
reportBlockedDangerousNavigation();
|
|
538
|
+
}
|
|
539
|
+
})
|
|
540
|
+
});
|
|
541
|
+
}
|
|
492
542
|
return /* @__PURE__ */ jsx(LinkStatusContext.Provider, {
|
|
493
543
|
value: linkStatusValue,
|
|
494
544
|
children: /* @__PURE__ */ jsx("a", {
|
|
@@ -501,6 +551,46 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
|
|
|
501
551
|
})
|
|
502
552
|
});
|
|
503
553
|
}
|
|
554
|
+
if (legacyBehavior) {
|
|
555
|
+
const child = React.Children.only(children);
|
|
556
|
+
if (process.env.NODE_ENV !== "production") {
|
|
557
|
+
if (onClick) console.warn(`"onClick" was passed to <Link> with \`href\` of \`${resolveHref(href)}\` but "legacyBehavior" was set. The legacy behavior requires onClick be set on the child of next/link`);
|
|
558
|
+
if (onMouseEnter) console.warn(`"onMouseEnter" was passed to <Link> with \`href\` of \`${resolveHref(href)}\` but "legacyBehavior" was set. The legacy behavior requires onMouseEnter be set on the child of next/link`);
|
|
559
|
+
}
|
|
560
|
+
const childPropsExisting = child.props;
|
|
561
|
+
const childHasOwnHref = child.type === "a" ? "href" in childPropsExisting : false;
|
|
562
|
+
const shouldForwardHref = passHref || child.type === "a" && !childHasOwnHref;
|
|
563
|
+
const childOnClick = childPropsExisting.onClick;
|
|
564
|
+
const childOnMouseEnter = childPropsExisting.onMouseEnter;
|
|
565
|
+
const childOnTouchStart = childPropsExisting.onTouchStart;
|
|
566
|
+
const childRef = childPropsExisting.ref;
|
|
567
|
+
const setLegacyRefs = (node) => {
|
|
568
|
+
internalRef.current = node;
|
|
569
|
+
if (typeof childRef === "function") childRef(node);
|
|
570
|
+
else if (childRef) childRef.current = node;
|
|
571
|
+
};
|
|
572
|
+
const clonedProps = {
|
|
573
|
+
ref: setLegacyRefs,
|
|
574
|
+
onClick: (event) => {
|
|
575
|
+
if (childOnClick) childOnClick(event);
|
|
576
|
+
if (event.defaultPrevented) return;
|
|
577
|
+
handleClick(event, { skipLinkOnClick: true });
|
|
578
|
+
},
|
|
579
|
+
onMouseEnter: (event) => {
|
|
580
|
+
if (childOnMouseEnter) childOnMouseEnter(event);
|
|
581
|
+
prefetchOnIntent();
|
|
582
|
+
},
|
|
583
|
+
onTouchStart: (event) => {
|
|
584
|
+
if (childOnTouchStart) childOnTouchStart(event);
|
|
585
|
+
prefetchOnIntent();
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
if (shouldForwardHref) clonedProps.href = fullHref;
|
|
589
|
+
return /* @__PURE__ */ jsx(LinkStatusContext.Provider, {
|
|
590
|
+
value: linkStatusValue,
|
|
591
|
+
children: React.cloneElement(child, clonedProps)
|
|
592
|
+
});
|
|
593
|
+
}
|
|
504
594
|
return /* @__PURE__ */ jsx(LinkStatusContext.Provider, {
|
|
505
595
|
value: linkStatusValue,
|
|
506
596
|
children: /* @__PURE__ */ jsx("a", {
|