vinext 0.1.2 → 0.1.4
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/client-build-config.d.ts +11 -2
- package/dist/build/client-build-config.js +17 -6
- package/dist/build/prerender.d.ts +9 -1
- package/dist/build/prerender.js +42 -12
- package/dist/build/run-prerender.d.ts +10 -2
- package/dist/build/run-prerender.js +15 -1
- package/dist/client/app-nav-failure-handler.d.ts +8 -0
- package/dist/client/app-nav-failure-handler.js +44 -0
- package/dist/client/pages-router-link-navigation.d.ts +33 -7
- package/dist/client/pages-router-link-navigation.js +32 -2
- package/dist/client/vinext-next-data.d.ts +18 -1
- package/dist/client/vinext-next-data.js +2 -0
- package/dist/client/window-next.d.ts +2 -1
- package/dist/client/window-next.js +12 -1
- package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
- package/dist/config/config-matchers.d.ts +11 -1
- package/dist/config/config-matchers.js +87 -16
- package/dist/config/next-config.d.ts +46 -4
- package/dist/config/next-config.js +147 -48
- package/dist/config/tsconfig-paths.js +14 -1
- package/dist/deploy.d.ts +30 -11
- package/dist/deploy.js +200 -112
- package/dist/entries/app-browser-entry.d.ts +9 -3
- package/dist/entries/app-browser-entry.js +21 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +65 -5
- package/dist/entries/app-rsc-manifest.js +2 -0
- package/dist/entries/app-ssr-entry.js +1 -1
- package/dist/entries/pages-client-entry.js +66 -20
- package/dist/entries/pages-server-entry.js +47 -31
- package/dist/index.js +417 -102
- package/dist/plugins/dynamic-preload-metadata.js +2 -4
- package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
- package/dist/plugins/extensionless-dynamic-import.js +152 -0
- package/dist/plugins/fonts.js +5 -4
- package/dist/plugins/optimize-imports.d.ts +2 -1
- package/dist/plugins/optimize-imports.js +11 -9
- package/dist/plugins/postcss.js +7 -7
- package/dist/plugins/strip-server-exports.d.ts +9 -7
- package/dist/plugins/strip-server-exports.js +493 -46
- package/dist/plugins/typeof-window.d.ts +14 -0
- package/dist/plugins/typeof-window.js +150 -0
- package/dist/routing/app-route-graph.d.ts +2 -1
- package/dist/routing/app-route-graph.js +46 -16
- package/dist/routing/file-matcher.d.ts +10 -1
- package/dist/routing/file-matcher.js +22 -1
- package/dist/routing/pages-router.js +3 -3
- package/dist/routing/utils.d.ts +35 -6
- package/dist/routing/utils.js +59 -7
- package/dist/server/api-handler.d.ts +6 -1
- package/dist/server/api-handler.js +21 -15
- package/dist/server/app-browser-action-result.d.ts +19 -6
- package/dist/server/app-browser-action-result.js +20 -11
- package/dist/server/app-browser-entry.js +175 -91
- package/dist/server/app-browser-error.d.ts +10 -6
- package/dist/server/app-browser-error.js +43 -8
- package/dist/server/app-browser-hydration.d.ts +2 -0
- package/dist/server/app-browser-hydration.js +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +5 -3
- package/dist/server/app-browser-navigation-controller.js +23 -2
- package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
- package/dist/server/app-browser-server-action-navigation.js +9 -0
- package/dist/server/app-browser-state.d.ts +1 -1
- package/dist/server/app-browser-state.js +19 -11
- package/dist/server/app-browser-stream.js +86 -43
- package/dist/server/app-browser-visible-commit.d.ts +1 -1
- package/dist/server/app-elements-wire.d.ts +6 -1
- package/dist/server/app-elements-wire.js +14 -4
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-fallback-renderer.d.ts +1 -0
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-optimistic-routing.js +2 -2
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +27 -14
- package/dist/server/app-page-cache-render.d.ts +53 -0
- package/dist/server/app-page-cache-render.js +91 -0
- package/dist/server/app-page-cache.d.ts +16 -2
- package/dist/server/app-page-cache.js +62 -1
- package/dist/server/app-page-dispatch.d.ts +26 -0
- package/dist/server/app-page-dispatch.js +149 -92
- package/dist/server/app-page-element-builder.d.ts +1 -0
- package/dist/server/app-page-element-builder.js +5 -2
- package/dist/server/app-page-execution.d.ts +6 -1
- package/dist/server/app-page-execution.js +21 -1
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +4 -0
- package/dist/server/app-page-render-observation.d.ts +3 -1
- package/dist/server/app-page-render-observation.js +17 -1
- package/dist/server/app-page-render.d.ts +12 -1
- package/dist/server/app-page-render.js +42 -4
- package/dist/server/app-page-request.d.ts +2 -0
- package/dist/server/app-page-request.js +2 -1
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +14 -5
- package/dist/server/app-page-stream.d.ts +15 -3
- package/dist/server/app-page-stream.js +11 -5
- package/dist/server/app-pages-bridge.d.ts +23 -1
- package/dist/server/app-pages-bridge.js +26 -17
- package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
- package/dist/server/app-ppr-fallback-shell-render.js +26 -0
- package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
- package/dist/server/app-ppr-fallback-shell.js +8 -1
- package/dist/server/app-route-handler-dispatch.js +9 -2
- package/dist/server/app-route-handler-policy.d.ts +1 -0
- package/dist/server/app-router-entry.js +5 -0
- package/dist/server/app-rsc-cache-busting.js +2 -0
- package/dist/server/app-rsc-handler.d.ts +28 -0
- package/dist/server/app-rsc-handler.js +195 -59
- package/dist/server/app-rsc-route-matching.d.ts +3 -0
- package/dist/server/app-rsc-route-matching.js +8 -2
- package/dist/server/app-segment-config.d.ts +9 -1
- package/dist/server/app-segment-config.js +12 -3
- package/dist/server/app-server-action-execution.d.ts +1 -0
- package/dist/server/app-server-action-execution.js +47 -15
- package/dist/server/app-ssr-entry.d.ts +2 -0
- package/dist/server/app-ssr-entry.js +84 -39
- package/dist/server/before-interactive-head.d.ts +17 -0
- package/dist/server/before-interactive-head.js +35 -0
- package/dist/server/cache-control.js +4 -0
- package/dist/server/csp.js +1 -4
- package/dist/server/dev-server.d.ts +2 -2
- package/dist/server/dev-server.js +321 -83
- package/dist/server/hybrid-route-priority.d.ts +22 -0
- package/dist/server/hybrid-route-priority.js +33 -0
- package/dist/server/image-optimization.d.ts +18 -9
- package/dist/server/image-optimization.js +37 -23
- package/dist/server/implicit-tags.d.ts +2 -1
- package/dist/server/implicit-tags.js +4 -1
- package/dist/server/middleware-matcher.js +12 -3
- package/dist/server/middleware-runtime.d.ts +3 -4
- package/dist/server/middleware-runtime.js +2 -0
- package/dist/server/navigation-planner.d.ts +135 -41
- package/dist/server/navigation-planner.js +138 -0
- package/dist/server/navigation-trace.d.ts +9 -1
- package/dist/server/navigation-trace.js +9 -1
- package/dist/server/operation-token.d.ts +40 -0
- package/dist/server/operation-token.js +85 -0
- package/dist/server/pages-api-route.d.ts +6 -0
- package/dist/server/pages-api-route.js +13 -2
- package/dist/server/pages-asset-tags.d.ts +2 -1
- package/dist/server/pages-asset-tags.js +6 -2
- package/dist/server/pages-data-route.d.ts +9 -2
- package/dist/server/pages-data-route.js +18 -6
- package/dist/server/pages-dev-module-url.d.ts +4 -0
- package/dist/server/pages-dev-module-url.js +15 -0
- package/dist/server/pages-document-initial-props.d.ts +4 -15
- package/dist/server/pages-document-initial-props.js +27 -56
- package/dist/server/pages-get-initial-props.d.ts +54 -4
- package/dist/server/pages-get-initial-props.js +43 -1
- package/dist/server/pages-i18n.js +2 -2
- package/dist/server/pages-node-compat.js +2 -2
- package/dist/server/pages-page-data.d.ts +11 -2
- package/dist/server/pages-page-data.js +207 -34
- package/dist/server/pages-page-handler.d.ts +4 -2
- package/dist/server/pages-page-handler.js +62 -23
- package/dist/server/pages-page-response.d.ts +4 -1
- package/dist/server/pages-page-response.js +11 -8
- package/dist/server/pages-readiness.js +1 -1
- package/dist/server/pages-request-pipeline.d.ts +8 -7
- package/dist/server/pages-request-pipeline.js +126 -47
- package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
- package/dist/server/pregenerated-concrete-paths.js +2 -19
- package/dist/server/prerender-manifest.d.ts +33 -0
- package/dist/server/prerender-manifest.js +54 -0
- package/dist/server/prerender-route-params.d.ts +1 -2
- package/dist/server/prod-server.d.ts +3 -1
- package/dist/server/prod-server.js +50 -13
- package/dist/server/request-pipeline.d.ts +3 -15
- package/dist/server/request-pipeline.js +58 -47
- package/dist/server/rsc-stream-hints.d.ts +5 -1
- package/dist/server/rsc-stream-hints.js +6 -1
- package/dist/server/seed-cache.js +10 -18
- package/dist/server/static-file-cache.js +16 -4
- package/dist/shims/app-router-scroll-state.d.ts +3 -1
- package/dist/shims/app-router-scroll-state.js +14 -2
- package/dist/shims/app-router-scroll.d.ts +3 -0
- package/dist/shims/app-router-scroll.js +28 -18
- package/dist/shims/before-interactive-context.d.ts +14 -3
- package/dist/shims/cache-runtime.js +3 -2
- package/dist/shims/cache.d.ts +1 -0
- package/dist/shims/cache.js +1 -1
- package/dist/shims/cdn-cache.d.ts +5 -5
- package/dist/shims/document.d.ts +15 -20
- package/dist/shims/document.js +5 -8
- package/dist/shims/dynamic-preload-chunks.js +6 -4
- package/dist/shims/error-boundary.d.ts +2 -0
- package/dist/shims/error-boundary.js +7 -0
- package/dist/shims/error.js +3 -2
- package/dist/shims/error.react-server.d.ts +9 -0
- package/dist/shims/error.react-server.js +6 -0
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +45 -20
- package/dist/shims/hash-scroll.js +6 -1
- package/dist/shims/headers.js +29 -4
- package/dist/shims/image.js +9 -2
- package/dist/shims/internal/als-registry.js +28 -1
- package/dist/shims/internal/app-route-detection.js +8 -17
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
- package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
- package/dist/shims/internal/navigation-untracked.d.ts +35 -0
- package/dist/shims/internal/navigation-untracked.js +55 -0
- package/dist/shims/internal/pages-data-fetch-dedup.d.ts +6 -7
- package/dist/shims/internal/pages-data-fetch-dedup.js +67 -14
- package/dist/shims/internal/pages-data-target.d.ts +7 -2
- package/dist/shims/internal/pages-data-target.js +17 -8
- package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
- package/dist/shims/internal/pages-router-accessor.js +13 -0
- package/dist/shims/internal/router-context.d.ts +2 -1
- package/dist/shims/internal/router-context.js +3 -1
- package/dist/shims/link.js +47 -19
- package/dist/shims/metadata.js +4 -4
- package/dist/shims/navigation.d.ts +8 -2
- package/dist/shims/navigation.js +63 -31
- package/dist/shims/ppr-fallback-shell.d.ts +5 -1
- package/dist/shims/ppr-fallback-shell.js +28 -7
- package/dist/shims/router.d.ts +18 -3
- package/dist/shims/router.js +512 -142
- package/dist/shims/script.js +8 -4
- package/dist/shims/server.d.ts +16 -1
- package/dist/shims/server.js +44 -12
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/built-asset-url.d.ts +4 -0
- package/dist/utils/built-asset-url.js +11 -0
- package/dist/utils/commonjs-loader.d.ts +16 -0
- package/dist/utils/commonjs-loader.js +100 -0
- package/dist/utils/deployment-id.d.ts +8 -0
- package/dist/utils/deployment-id.js +22 -0
- package/dist/utils/has-trailing-comma.d.ts +24 -0
- package/dist/utils/has-trailing-comma.js +62 -0
- package/dist/utils/html-limited-bots.d.ts +18 -1
- package/dist/utils/html-limited-bots.js +23 -1
- package/dist/utils/parse-cookie.d.ts +13 -0
- package/dist/utils/parse-cookie.js +52 -0
- package/dist/utils/path.d.ts +7 -1
- package/dist/utils/path.js +9 -1
- package/dist/utils/text-stream.d.ts +1 -1
- package/dist/utils/text-stream.js +2 -2
- package/dist/utils/vite-version.d.ts +12 -1
- package/dist/utils/vite-version.js +9 -1
- package/package.json +2 -2
- package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
- package/dist/shims/internal/parse-cookie-header.js +0 -30
package/dist/shims/router.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { splitPathSegments } from "../routing/utils.js";
|
|
2
2
|
import { removeTrailingSlash, stripBasePath } from "../utils/base-path.js";
|
|
3
3
|
import { assertSafeNavigationUrl } from "./url-safety.js";
|
|
4
|
-
import { matchRoutePattern, routePatternParts } from "../routing/route-pattern.js";
|
|
4
|
+
import { fillRoutePatternSegments, matchRoutePattern, routePatternParts } from "../routing/route-pattern.js";
|
|
5
5
|
import { isUnknownRecord } from "../utils/record.js";
|
|
6
6
|
import { AppRouterContext } from "./internal/app-router-context.js";
|
|
7
7
|
import { RouterContext } from "./internal/router-context.js";
|
|
@@ -9,16 +9,18 @@ import { applyVinextLocaleGlobals, extractVinextNextDataJson, parseVinextNextDat
|
|
|
9
9
|
import { isValidModulePath } from "../client/validate-module-path.js";
|
|
10
10
|
import { addLocalePrefix, getDomainLocaleUrl, getLocalePathPrefix } from "../utils/domain-locale.js";
|
|
11
11
|
import { buildPagesDataHref } from "./internal/pages-data-url.js";
|
|
12
|
+
import { NEXT_DEPLOYMENT_ID_HEADER, getDeploymentId } from "../utils/deployment-id.js";
|
|
13
|
+
import { dedupedPagesDataFetch } from "./internal/pages-data-fetch-dedup.js";
|
|
12
14
|
import { prefetchPagesData, resolvePagesDataNavigationTarget } from "./internal/pages-data-target.js";
|
|
15
|
+
import { addQueryParam, appendSearchParamsToUrl, mergeRouteParamsIntoQuery, parseQueryString, urlQueryToSearchParams } from "../utils/query.js";
|
|
16
|
+
import { resolveHybridClientRouteOwner } from "./internal/hybrid-client-route-owner.js";
|
|
13
17
|
import { getPagesRouterComponentsMap, markAppRouteDetectedOnPrefetch } from "./internal/app-route-detection.js";
|
|
14
|
-
import { dedupedPagesDataFetch } from "./internal/pages-data-fetch-dedup.js";
|
|
15
18
|
import { installWindowNext } from "../client/window-next.js";
|
|
16
19
|
import { getWindowOrigin, isAbsoluteOrProtocolRelativeUrl, isHashOnlyBrowserUrlChange, normalizePathTrailingSlash, toBrowserNavigationHref, toSameOriginAppPath, withBasePath } from "./url-utils.js";
|
|
17
|
-
import { addQueryParam, appendSearchParamsToUrl, mergeRouteParamsIntoQuery, parseQueryString, urlQueryToSearchParams } from "../utils/query.js";
|
|
18
20
|
import { scrollToHashTarget } from "./hash-scroll.js";
|
|
19
|
-
import { setPagesRouterPopStateHandler, setStampInitialHistoryState } from "./pages-router-runtime.js";
|
|
21
|
+
import { installPagesRouterRuntime, setPagesRouterPopStateHandler, setStampInitialHistoryState } from "./pages-router-runtime.js";
|
|
20
22
|
import { getCurrentBrowserLocale } from "./client-locale.js";
|
|
21
|
-
import { createElement, useContext, useEffect, useMemo, useState } from "react";
|
|
23
|
+
import { Component, Fragment, createElement, useContext, useEffect, useLayoutEffect, useMemo, useState } from "react";
|
|
22
24
|
//#region src/shims/router.ts
|
|
23
25
|
/**
|
|
24
26
|
* next/router shim
|
|
@@ -31,6 +33,134 @@ import { createElement, useContext, useEffect, useMemo, useState } from "react";
|
|
|
31
33
|
const __basePath = process.env.__NEXT_ROUTER_BASEPATH ?? "";
|
|
32
34
|
/** trailingSlash from next.config.js, injected by the plugin at build time */
|
|
33
35
|
const __trailingSlash = process.env.__VINEXT_TRAILING_SLASH === "true";
|
|
36
|
+
/** experimental.scrollRestoration from next.config.js, injected by the plugin at build time */
|
|
37
|
+
const __scrollRestoration = process.env.__NEXT_SCROLL_RESTORATION === "true";
|
|
38
|
+
const noopCommit = () => {};
|
|
39
|
+
const SCROLL_RESTORE_MAX_FRAMES = 60;
|
|
40
|
+
const SCROLL_RESTORE_TOLERANCE_PX = 1;
|
|
41
|
+
/**
|
|
42
|
+
* A version of useLayoutEffect that doesn't warn during SSR.
|
|
43
|
+
* `wrapWithRouterContext` is shared with the server-side Pages Router render
|
|
44
|
+
* path, where a raw useLayoutEffect would log React's "useLayoutEffect does
|
|
45
|
+
* nothing on the server" warning on every render. Same pattern as
|
|
46
|
+
* `shims/image.tsx`; Next.js only runs the commit callback on the client.
|
|
47
|
+
*/
|
|
48
|
+
const useNonWarningLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
49
|
+
var PagesRouterCommitBoundary = class extends Component {
|
|
50
|
+
componentDidCatch(error) {
|
|
51
|
+
this.props.onError(error);
|
|
52
|
+
}
|
|
53
|
+
render() {
|
|
54
|
+
return createElement(PagesRouterCommitBoundaryHelper, { onCommit: this.props.onCommit }, this.props.children);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
function PagesRouterCommitBoundaryHelper({ children, onCommit }) {
|
|
58
|
+
useNonWarningLayoutEffect(() => {
|
|
59
|
+
onCommit();
|
|
60
|
+
}, [onCommit]);
|
|
61
|
+
return createElement(Fragment, null, children);
|
|
62
|
+
}
|
|
63
|
+
function renderPagesRouterElement(element, scroll) {
|
|
64
|
+
const root = window.__VINEXT_ROOT__;
|
|
65
|
+
if (!root) return Promise.resolve();
|
|
66
|
+
cancelPreviousRenderCommit();
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
const cancel = () => {
|
|
69
|
+
if (routerRuntimeState.cancelPendingRenderCommit === cancel) routerRuntimeState.cancelPendingRenderCommit = null;
|
|
70
|
+
reject(new NavigationCancelledError("superseded"));
|
|
71
|
+
};
|
|
72
|
+
routerRuntimeState.cancelPendingRenderCommit = cancel;
|
|
73
|
+
const clearIfCurrent = () => {
|
|
74
|
+
if (routerRuntimeState.cancelPendingRenderCommit === cancel) routerRuntimeState.cancelPendingRenderCommit = null;
|
|
75
|
+
};
|
|
76
|
+
const isCurrent = () => routerRuntimeState.cancelPendingRenderCommit === cancel;
|
|
77
|
+
const scrollHandler = async () => {
|
|
78
|
+
if (scroll) await restorePagesRouterScrollPosition(scroll, isCurrent);
|
|
79
|
+
};
|
|
80
|
+
root.render(wrapWithRouterContext(element, () => {
|
|
81
|
+
(async () => {
|
|
82
|
+
if (!isCurrent()) return;
|
|
83
|
+
try {
|
|
84
|
+
await scrollHandler();
|
|
85
|
+
if (!isCurrent()) return;
|
|
86
|
+
clearIfCurrent();
|
|
87
|
+
resolve();
|
|
88
|
+
} catch (err) {
|
|
89
|
+
clearIfCurrent();
|
|
90
|
+
reject(err);
|
|
91
|
+
}
|
|
92
|
+
})();
|
|
93
|
+
}, (error) => {
|
|
94
|
+
clearIfCurrent();
|
|
95
|
+
reject(error);
|
|
96
|
+
}));
|
|
97
|
+
if (!hasBrowserDocument()) {
|
|
98
|
+
clearIfCurrent();
|
|
99
|
+
resolve();
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function hasBrowserDocument() {
|
|
104
|
+
return typeof document !== "undefined" && document.documentElement !== void 0;
|
|
105
|
+
}
|
|
106
|
+
async function restorePagesRouterScrollPosition(scroll, shouldContinue) {
|
|
107
|
+
if (!shouldContinue()) return;
|
|
108
|
+
scrollToPagesRouterPosition(scroll);
|
|
109
|
+
if (isAtScrollPosition(scroll)) return;
|
|
110
|
+
let previousScrollPosition = getWindowScrollPosition();
|
|
111
|
+
for (let frame = 0; frame < SCROLL_RESTORE_MAX_FRAMES; frame += 1) {
|
|
112
|
+
await waitForNextAnimationFrame();
|
|
113
|
+
if (!shouldContinue()) return;
|
|
114
|
+
scrollToPagesRouterPosition(scroll);
|
|
115
|
+
if (isAtScrollPosition(scroll)) return;
|
|
116
|
+
const currentScrollPosition = getWindowScrollPosition();
|
|
117
|
+
if (currentScrollPosition.x === previousScrollPosition.x && currentScrollPosition.y === previousScrollPosition.y) break;
|
|
118
|
+
previousScrollPosition = currentScrollPosition;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function scrollToPagesRouterPosition({ x, y }) {
|
|
122
|
+
if (!hasBrowserDocument()) {
|
|
123
|
+
window.scrollTo(x, y);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const htmlElement = document.documentElement;
|
|
127
|
+
if (!(htmlElement.dataset.scrollBehavior === "smooth")) {
|
|
128
|
+
window.scrollTo(x, y);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const previousScrollBehavior = htmlElement.style.scrollBehavior;
|
|
132
|
+
htmlElement.style.scrollBehavior = "auto";
|
|
133
|
+
htmlElement.getClientRects();
|
|
134
|
+
window.scrollTo(x, y);
|
|
135
|
+
htmlElement.style.scrollBehavior = previousScrollBehavior;
|
|
136
|
+
}
|
|
137
|
+
function isAtScrollPosition({ x, y }) {
|
|
138
|
+
return Math.abs(window.scrollX - x) <= SCROLL_RESTORE_TOLERANCE_PX && Math.abs(window.scrollY - y) <= SCROLL_RESTORE_TOLERANCE_PX;
|
|
139
|
+
}
|
|
140
|
+
function waitForNextAnimationFrame() {
|
|
141
|
+
return new Promise((resolve) => {
|
|
142
|
+
if (typeof requestAnimationFrame === "function") {
|
|
143
|
+
requestAnimationFrame(() => resolve());
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
setTimeout(resolve, 16);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function canUseSessionStorageForScrollRestoration() {
|
|
150
|
+
if (typeof window === "undefined") return false;
|
|
151
|
+
try {
|
|
152
|
+
const key = "__next";
|
|
153
|
+
window.sessionStorage.setItem(key, key);
|
|
154
|
+
window.sessionStorage.removeItem(key);
|
|
155
|
+
return true;
|
|
156
|
+
} catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const manualScrollRestoration = __scrollRestoration && typeof window !== "undefined" && window.next?.appDir !== true && "scrollRestoration" in window.history && canUseSessionStorageForScrollRestoration();
|
|
161
|
+
function installManualScrollRestoration() {
|
|
162
|
+
if (manualScrollRestoration) window.history.scrollRestoration = "manual";
|
|
163
|
+
}
|
|
34
164
|
function createRouterEvents() {
|
|
35
165
|
const listeners = /* @__PURE__ */ new Map();
|
|
36
166
|
return {
|
|
@@ -46,14 +176,58 @@ function createRouterEvents() {
|
|
|
46
176
|
}
|
|
47
177
|
};
|
|
48
178
|
}
|
|
49
|
-
const
|
|
179
|
+
const PAGES_ROUTER_RUNTIME_STATE_KEY = Symbol.for("vinext.pagesRouter.runtimeState");
|
|
180
|
+
function createPagesRouterRuntimeState() {
|
|
181
|
+
return {
|
|
182
|
+
events: createRouterEvents(),
|
|
183
|
+
historyKeyCounter: 0,
|
|
184
|
+
navigationId: 0,
|
|
185
|
+
activeAbortController: null,
|
|
186
|
+
cancelPendingRenderCommit: null,
|
|
187
|
+
lastPathnameAndSearch: typeof window !== "undefined" ? window.location.pathname + window.location.search : "",
|
|
188
|
+
isFirstPopStateEvent: true,
|
|
189
|
+
routerDidNavigate: false,
|
|
190
|
+
deprecatedEventBridgeInstalled: false,
|
|
191
|
+
pagesRouterReady: typeof window === "undefined" || !shouldDeferInitialPagesRouterReady()
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function getPagesRouterRuntimeState() {
|
|
195
|
+
if (typeof window === "undefined") return createPagesRouterRuntimeState();
|
|
196
|
+
const globalObject = window;
|
|
197
|
+
const existing = globalObject[PAGES_ROUTER_RUNTIME_STATE_KEY];
|
|
198
|
+
if (existing) return existing;
|
|
199
|
+
const state = createPagesRouterRuntimeState();
|
|
200
|
+
globalObject[PAGES_ROUTER_RUNTIME_STATE_KEY] = state;
|
|
201
|
+
return state;
|
|
202
|
+
}
|
|
203
|
+
const routerRuntimeState = getPagesRouterRuntimeState();
|
|
204
|
+
const routerEvents = routerRuntimeState.events;
|
|
205
|
+
function getPagesRouterRuntimeComponents() {
|
|
206
|
+
const existing = routerRuntimeState.components;
|
|
207
|
+
if (existing) return existing;
|
|
208
|
+
const components = {
|
|
209
|
+
CommitBoundary: PagesRouterCommitBoundary,
|
|
210
|
+
Provider: PagesRouterProvider
|
|
211
|
+
};
|
|
212
|
+
routerRuntimeState.components = components;
|
|
213
|
+
return components;
|
|
214
|
+
}
|
|
50
215
|
function resolveUrl(url) {
|
|
51
216
|
if (typeof url === "string") return url;
|
|
52
|
-
|
|
53
|
-
|
|
217
|
+
const hasQuery = url.query !== void 0 && Object.keys(url.query).length > 0;
|
|
218
|
+
const hasSearch = typeof url.search === "string" && url.search.length > 0;
|
|
219
|
+
const hasHash = typeof url.hash === "string" && url.hash.length > 0;
|
|
220
|
+
const inheritsVisiblePath = url.pathname === void 0 && (hasQuery || hasSearch || hasHash);
|
|
221
|
+
let result = url.pathname ?? (typeof window !== "undefined" ? inheritsVisiblePath ? stripBasePath(window.location.pathname, __basePath) : window.__NEXT_DATA__?.page ?? stripBasePath(window.location.pathname, __basePath) : "/");
|
|
222
|
+
if (hasSearch) {
|
|
223
|
+
const search = url.search.startsWith("?") ? url.search : `?${url.search}`;
|
|
224
|
+
const hashIndex = search.indexOf("#");
|
|
225
|
+
result += hashIndex === -1 ? search : `${search.slice(0, hashIndex)}%23${search.slice(hashIndex + 1)}`;
|
|
226
|
+
} else if (hasQuery) {
|
|
54
227
|
const params = urlQueryToSearchParams(url.query);
|
|
55
228
|
result = appendSearchParamsToUrl(result, params);
|
|
56
|
-
}
|
|
229
|
+
} else if (hasHash && typeof window !== "undefined") result += window.location.search;
|
|
230
|
+
if (hasHash) result += url.hash.startsWith("#") ? url.hash : `#${url.hash}`;
|
|
57
231
|
return result;
|
|
58
232
|
}
|
|
59
233
|
/**
|
|
@@ -65,8 +239,39 @@ function resolveUrl(url) {
|
|
|
65
239
|
* Pages error routes are handled as a narrow exception below because Next.js
|
|
66
240
|
* treats their href as the component route while preserving `as` in history.
|
|
67
241
|
*/
|
|
68
|
-
function resolveNavigationTarget(url, as, locale) {
|
|
69
|
-
return applyNavigationLocale(as ?? resolveUrl(url), locale);
|
|
242
|
+
function resolveNavigationTarget(url, as, locale, replaceExistingLocale = false) {
|
|
243
|
+
return applyNavigationLocale(as ?? resolveUrl(url), locale, replaceExistingLocale);
|
|
244
|
+
}
|
|
245
|
+
var HrefInterpolationError = class extends Error {};
|
|
246
|
+
function interpolateCurrentDynamicRoute(resolved) {
|
|
247
|
+
if (typeof window === "undefined") return resolved;
|
|
248
|
+
const routePattern = window.__NEXT_DATA__?.page;
|
|
249
|
+
if (!routePattern || extractRouteParamNames(routePattern).length === 0) return resolved;
|
|
250
|
+
try {
|
|
251
|
+
const target = new URL(resolved, "http://vinext.local");
|
|
252
|
+
const currentOrigin = getWindowOrigin();
|
|
253
|
+
if (currentOrigin && target.origin !== "http://vinext.local" && target.origin !== currentOrigin) return resolved;
|
|
254
|
+
const visiblePath = stripBasePath(window.location.pathname, __basePath);
|
|
255
|
+
const visibleLocale = getLocalePathPrefix(visiblePath, window.__VINEXT_LOCALES__);
|
|
256
|
+
if (extractRouteParamsFromPath(routePattern, visibleLocale ? visiblePath.slice(visibleLocale.length + 1) || "/" : visiblePath) === null) return resolved;
|
|
257
|
+
const query = parseQueryString(target.search);
|
|
258
|
+
const missingParams = routePatternParts(routePattern).filter((part) => part.startsWith(":") && !part.endsWith("*")).map((part) => part.slice(1, part.endsWith("+") ? -1 : void 0)).filter((paramName) => {
|
|
259
|
+
const value = query[paramName];
|
|
260
|
+
return value === void 0 || value === "" || Array.isArray(value) && value.length === 0;
|
|
261
|
+
});
|
|
262
|
+
if (missingParams.length > 0) throw new HrefInterpolationError(`The provided \`href\` (${`${routePattern}${target.search}${target.hash}`}) value is missing query values (${missingParams.join(", ")}) to be interpolated properly. Read more: https://nextjs.org/docs/messages/href-interpolation-failed`);
|
|
263
|
+
const routeParams = getRouteParamsFromQuery(routePattern, query);
|
|
264
|
+
if (!routeParams) return resolved;
|
|
265
|
+
const pathname = fillRoutePatternSegments(routePattern, Object.fromEntries(Object.entries(routeParams).map(([key, value]) => [key, Array.isArray(value) ? value.map(encodeURIComponent) : encodeURIComponent(value)])));
|
|
266
|
+
if (!pathname) return resolved;
|
|
267
|
+
const targetLocale = getLocalePathPrefix(target.pathname, window.__VINEXT_LOCALES__);
|
|
268
|
+
target.pathname = targetLocale ? `/${targetLocale}${pathname}` : pathname;
|
|
269
|
+
for (const paramName of extractRouteParamNames(routePattern)) target.searchParams.delete(paramName);
|
|
270
|
+
return target.href.slice(target.origin.length);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
if (error instanceof HrefInterpolationError) throw error;
|
|
273
|
+
return resolved;
|
|
274
|
+
}
|
|
70
275
|
}
|
|
71
276
|
function getCurrentUrlLocale() {
|
|
72
277
|
return getCurrentBrowserLocale({
|
|
@@ -131,13 +336,26 @@ function getDomainLocalePath(url, locale) {
|
|
|
131
336
|
* Apply locale prefix to a URL for client-side navigation.
|
|
132
337
|
* Same logic as Link's applyLocaleToHref but reads from window globals.
|
|
133
338
|
*/
|
|
134
|
-
function applyNavigationLocale(url, locale) {
|
|
339
|
+
function applyNavigationLocale(url, locale, replaceExistingLocale = false) {
|
|
135
340
|
if (!locale || typeof window === "undefined") return url;
|
|
136
341
|
if (isAbsoluteOrProtocolRelativeUrl(url)) return url;
|
|
137
|
-
if (getLocalePathPrefix(url, window.__VINEXT_LOCALES__)) return url;
|
|
138
|
-
const
|
|
342
|
+
if (!replaceExistingLocale && getLocalePathPrefix(url, window.__VINEXT_LOCALES__)) return url;
|
|
343
|
+
const normalizedUrl = replaceExistingLocale ? removeNavigationLocalePrefix(url) : url;
|
|
344
|
+
const domainLocalePath = getDomainLocalePath(normalizedUrl, locale);
|
|
139
345
|
if (domainLocalePath) return domainLocalePath;
|
|
140
|
-
return addLocalePrefix(
|
|
346
|
+
return addLocalePrefix(normalizedUrl, locale, window.__VINEXT_DEFAULT_LOCALE__ ?? "");
|
|
347
|
+
}
|
|
348
|
+
function removeNavigationLocalePrefix(url) {
|
|
349
|
+
const locales = window.__VINEXT_LOCALES__;
|
|
350
|
+
if (!locales?.length) return url;
|
|
351
|
+
try {
|
|
352
|
+
const parsed = new URL(url, "http://vinext.local");
|
|
353
|
+
const locale = getLocalePathPrefix(parsed.pathname, locales);
|
|
354
|
+
if (!locale) return url;
|
|
355
|
+
return `${parsed.pathname.slice(locale.length + 1) || "/"}${parsed.search}${parsed.hash}`;
|
|
356
|
+
} catch {
|
|
357
|
+
return url;
|
|
358
|
+
}
|
|
141
359
|
}
|
|
142
360
|
function isDefaultLocaleRootNavigation(url, locale) {
|
|
143
361
|
if (typeof window === "undefined") return false;
|
|
@@ -201,8 +419,16 @@ function buildInitialRouterState() {
|
|
|
201
419
|
* locale stamped before any push could overwrite the active locale global.
|
|
202
420
|
*/
|
|
203
421
|
function stampInitialHistoryState() {
|
|
204
|
-
|
|
205
|
-
window.history
|
|
422
|
+
installManualScrollRestoration();
|
|
423
|
+
if (!window.history) return;
|
|
424
|
+
const existingState = window.history.state;
|
|
425
|
+
if (existingState !== null && existingState !== void 0) {
|
|
426
|
+
routerRuntimeState.currentHistoryKey = getRouterStateKey(existingState) ?? routerRuntimeState.currentHistoryKey;
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
const initialState = buildInitialRouterState();
|
|
430
|
+
routerRuntimeState.currentHistoryKey = initialState.key;
|
|
431
|
+
window.history.replaceState(initialState, "");
|
|
206
432
|
}
|
|
207
433
|
setStampInitialHistoryState(stampInitialHistoryState);
|
|
208
434
|
/** Save current scroll position into history state for back/forward restoration.
|
|
@@ -213,22 +439,62 @@ setStampInitialHistoryState(stampInitialHistoryState);
|
|
|
213
439
|
* minting the same shape here so the entry isn't treated as foreign.
|
|
214
440
|
*/
|
|
215
441
|
function saveScrollPosition() {
|
|
216
|
-
const
|
|
442
|
+
const position = getWindowScrollPosition();
|
|
443
|
+
const existing = isUnknownRecord(window.history.state) ? window.history.state : null;
|
|
217
444
|
const scroll = {
|
|
218
|
-
__vinext_scrollX:
|
|
219
|
-
__vinext_scrollY:
|
|
445
|
+
__vinext_scrollX: position.x,
|
|
446
|
+
__vinext_scrollY: position.y
|
|
220
447
|
};
|
|
221
448
|
const base = existing ?? buildInitialRouterState();
|
|
449
|
+
const key = getRouterStateKey(base);
|
|
450
|
+
if (key !== void 0) {
|
|
451
|
+
routerRuntimeState.currentHistoryKey = key;
|
|
452
|
+
saveScrollPositionToSessionStorage(key, position);
|
|
453
|
+
}
|
|
222
454
|
window.history.replaceState({
|
|
223
455
|
...base,
|
|
224
456
|
...scroll
|
|
225
457
|
}, "");
|
|
226
458
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
459
|
+
function getWindowScrollPosition() {
|
|
460
|
+
return {
|
|
461
|
+
x: window.scrollX,
|
|
462
|
+
y: window.scrollY
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
function getScrollStorageKey(historyKey) {
|
|
466
|
+
return `__next_scroll_${historyKey}`;
|
|
467
|
+
}
|
|
468
|
+
function readScrollPosition(value) {
|
|
469
|
+
if (!isUnknownRecord(value)) return null;
|
|
470
|
+
const nextX = value.x;
|
|
471
|
+
const nextY = value.y;
|
|
472
|
+
if (typeof nextX === "number" && typeof nextY === "number") return {
|
|
473
|
+
x: nextX,
|
|
474
|
+
y: nextY
|
|
475
|
+
};
|
|
476
|
+
const vinextX = value.__vinext_scrollX;
|
|
477
|
+
const vinextY = value.__vinext_scrollY;
|
|
478
|
+
if (typeof vinextX === "number" && typeof vinextY === "number") return {
|
|
479
|
+
x: vinextX,
|
|
480
|
+
y: vinextY
|
|
481
|
+
};
|
|
482
|
+
return null;
|
|
483
|
+
}
|
|
484
|
+
function saveScrollPositionToSessionStorage(key, position) {
|
|
485
|
+
if (!manualScrollRestoration) return;
|
|
486
|
+
try {
|
|
487
|
+
window.sessionStorage.setItem(getScrollStorageKey(key), JSON.stringify(position));
|
|
488
|
+
} catch {}
|
|
489
|
+
}
|
|
490
|
+
function readScrollPositionFromSessionStorage(key) {
|
|
491
|
+
if (!manualScrollRestoration) return null;
|
|
492
|
+
try {
|
|
493
|
+
const value = window.sessionStorage.getItem(getScrollStorageKey(key));
|
|
494
|
+
if (value === null) return null;
|
|
495
|
+
return readScrollPosition(JSON.parse(value));
|
|
496
|
+
} catch {
|
|
497
|
+
return null;
|
|
232
498
|
}
|
|
233
499
|
}
|
|
234
500
|
let _ssrContext = null;
|
|
@@ -380,6 +646,11 @@ function getRouteParamsFromQuery(pattern, query) {
|
|
|
380
646
|
function getRouteQueryFromNextData(nextData, resolvedPath) {
|
|
381
647
|
const routeQuery = {};
|
|
382
648
|
if (!nextData?.query || !nextData.page) return routeQuery;
|
|
649
|
+
if (extractRouteParamsFromPath(nextData.page, resolvedPath) === null) {
|
|
650
|
+
for (const [key, value] of Object.entries(nextData.query)) if (typeof value === "string") routeQuery[key] = value;
|
|
651
|
+
else if (Array.isArray(value)) routeQuery[key] = [...value];
|
|
652
|
+
return routeQuery;
|
|
653
|
+
}
|
|
383
654
|
const routeParamNames = extractRouteParamNames(nextData.page);
|
|
384
655
|
if (routeParamNames.length === 0) return routeQuery;
|
|
385
656
|
const currentRouteParams = extractRouteParamsFromPath(nextData.page, resolvedPath);
|
|
@@ -422,9 +693,23 @@ function getPathnameAndQuery() {
|
|
|
422
693
|
...searchQuery,
|
|
423
694
|
...routeQuery
|
|
424
695
|
},
|
|
425
|
-
asPath: resolvedPath + window.location.search + window.location.hash
|
|
696
|
+
asPath: getCurrentHistoryAsPath() ?? resolvedPath + window.location.search + window.location.hash
|
|
426
697
|
};
|
|
427
698
|
}
|
|
699
|
+
function getCurrentHistoryAsPath() {
|
|
700
|
+
const state = window.history?.state;
|
|
701
|
+
if (!isNextRouterState(state) || typeof state.as !== "string") return null;
|
|
702
|
+
try {
|
|
703
|
+
const browserUrl = new URL(window.location.href);
|
|
704
|
+
const stateUrl = new URL(toBrowserNavigationHref(state.as, window.location.href, __basePath), window.location.href);
|
|
705
|
+
if (stateUrl.pathname !== browserUrl.pathname || stateUrl.search !== browserUrl.search) return null;
|
|
706
|
+
const stateAs = stripHash(state.as);
|
|
707
|
+
const visibleAs = `${stripBasePath(window.location.pathname, __basePath)}${window.location.search}`;
|
|
708
|
+
return `${stateAs || visibleAs}${window.location.hash}`;
|
|
709
|
+
} catch {
|
|
710
|
+
return null;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
428
713
|
function getPagesNavigationIsReadyFromSerializedState(routePattern, searchString, nextData) {
|
|
429
714
|
if (!routePattern) return true;
|
|
430
715
|
if (nextData?.gssp === true || nextData?.gip === true || nextData?.isExperimentalCompile === true || nextData?.appGip === true && nextData.gsp !== true) return true;
|
|
@@ -439,9 +724,8 @@ function shouldDeferInitialPagesRouterReady() {
|
|
|
439
724
|
if (!nextData) return false;
|
|
440
725
|
return !getPagesNavigationIsReadyFromSerializedState(nextData.page, window.location.search, nextData);
|
|
441
726
|
}
|
|
442
|
-
let _pagesRouterReady = typeof window === "undefined" ? true : !shouldDeferInitialPagesRouterReady();
|
|
443
727
|
function isPagesRouterReady() {
|
|
444
|
-
return
|
|
728
|
+
return routerRuntimeState.pagesRouterReady;
|
|
445
729
|
}
|
|
446
730
|
function isPagesRouterDocumentActive() {
|
|
447
731
|
if (typeof window === "undefined") return true;
|
|
@@ -451,10 +735,28 @@ function isPagesRouterDocumentActive() {
|
|
|
451
735
|
return Boolean(window.__VINEXT_APP__ || window.__VINEXT_APP_LOADER__);
|
|
452
736
|
}
|
|
453
737
|
function markPagesRouterReady() {
|
|
454
|
-
if (typeof window === "undefined" ||
|
|
455
|
-
|
|
738
|
+
if (typeof window === "undefined" || routerRuntimeState.pagesRouterReady) return false;
|
|
739
|
+
routerRuntimeState.pagesRouterReady = true;
|
|
456
740
|
return true;
|
|
457
741
|
}
|
|
742
|
+
function initializePagesRouterReadyFromNextData(nextData) {
|
|
743
|
+
if (typeof window === "undefined") return;
|
|
744
|
+
routerRuntimeState.pagesRouterReady = getPagesNavigationIsReadyFromSerializedState(nextData.page, window.location.search, nextData);
|
|
745
|
+
}
|
|
746
|
+
function markPagesRouterHydrated() {
|
|
747
|
+
if (typeof window === "undefined" || window.__NEXT_HYDRATED === true) return;
|
|
748
|
+
const hydratedAt = performance.now();
|
|
749
|
+
window.__VINEXT_HYDRATED_AT = hydratedAt;
|
|
750
|
+
window.__NEXT_HYDRATED = true;
|
|
751
|
+
window.__NEXT_HYDRATED_AT = hydratedAt;
|
|
752
|
+
window.__NEXT_HYDRATED_CB?.();
|
|
753
|
+
}
|
|
754
|
+
function PagesRouterHydrationMarker() {
|
|
755
|
+
useEffect(() => {
|
|
756
|
+
markPagesRouterHydrated();
|
|
757
|
+
}, []);
|
|
758
|
+
return null;
|
|
759
|
+
}
|
|
458
760
|
function getRouterSnapshot() {
|
|
459
761
|
const isReady = typeof window === "undefined" ? _getSSRContext()?.navigationIsReady ?? true : isPagesRouterReady();
|
|
460
762
|
return {
|
|
@@ -488,20 +790,10 @@ var HardNavigationScheduledError = class extends Error {
|
|
|
488
790
|
this.name = "HardNavigationScheduledError";
|
|
489
791
|
}
|
|
490
792
|
};
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
* the active one. If a newer navigation has started, the stale one
|
|
496
|
-
* throws NavigationCancelledError so the caller can emit routeChangeError
|
|
497
|
-
* and skip routeChangeComplete.
|
|
498
|
-
*
|
|
499
|
-
* Replaces the old boolean `_navInProgress` guard which silently dropped
|
|
500
|
-
* the second navigation, causing URL/content mismatch.
|
|
501
|
-
*/
|
|
502
|
-
let _navigationId = 0;
|
|
503
|
-
/** AbortController for the in-flight fetch, so superseded navigations abort network I/O. */
|
|
504
|
-
let _activeAbortController = null;
|
|
793
|
+
function cancelPreviousRenderCommit() {
|
|
794
|
+
routerRuntimeState.cancelPendingRenderCommit?.();
|
|
795
|
+
routerRuntimeState.cancelPendingRenderCommit = null;
|
|
796
|
+
}
|
|
505
797
|
function scheduleHardNavigationAndThrow(url, message) {
|
|
506
798
|
if (typeof window === "undefined") throw new HardNavigationScheduledError(message);
|
|
507
799
|
window.location.href = url;
|
|
@@ -566,15 +858,23 @@ function getMiddlewarePagesDataFetchUrl(browserUrl) {
|
|
|
566
858
|
if (parsed.origin !== getWindowOrigin()) return null;
|
|
567
859
|
return buildPagesDataHref(__basePath, buildId, stripBasePath(parsed.pathname, __basePath), parsed.search);
|
|
568
860
|
}
|
|
569
|
-
async function
|
|
861
|
+
async function resolveMiddlewareDataEffect(browserUrl, signal) {
|
|
570
862
|
const dataUrl = getMiddlewarePagesDataFetchUrl(browserUrl);
|
|
571
863
|
if (!dataUrl) return null;
|
|
572
864
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
573
865
|
try {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
866
|
+
const res = await dedupedPagesDataFetch(dataUrl, {
|
|
867
|
+
headers: {
|
|
868
|
+
Accept: "application/json",
|
|
869
|
+
"x-nextjs-data": "1"
|
|
870
|
+
},
|
|
871
|
+
signal
|
|
872
|
+
});
|
|
873
|
+
return {
|
|
874
|
+
redirectLocation: res.headers.get("x-nextjs-redirect"),
|
|
875
|
+
rewriteTarget: res.headers.get("x-nextjs-rewrite"),
|
|
876
|
+
response: res
|
|
877
|
+
};
|
|
578
878
|
} catch {
|
|
579
879
|
return null;
|
|
580
880
|
}
|
|
@@ -611,19 +911,24 @@ function handleDataRedirect(destination, redirectBasePath, mode = "push") {
|
|
|
611
911
|
* data endpoint returns 404 and the client lands on the new build via a
|
|
612
912
|
* full document load.
|
|
613
913
|
*/
|
|
614
|
-
async function navigateClientData(url,
|
|
615
|
-
|
|
616
|
-
if (!root) {
|
|
914
|
+
async function navigateClientData(url, initialTarget, controller, navId, assertStillCurrent, options = {}, prefetchedResponse) {
|
|
915
|
+
if (!window.__VINEXT_ROOT__) {
|
|
617
916
|
window.location.href = url;
|
|
618
917
|
return;
|
|
619
918
|
}
|
|
620
919
|
if (controller.signal.aborted) throw new NavigationCancelledError(url);
|
|
621
|
-
let res;
|
|
622
|
-
try {
|
|
623
|
-
|
|
920
|
+
let res = prefetchedResponse;
|
|
921
|
+
if (!res) try {
|
|
922
|
+
const headers = {
|
|
624
923
|
Accept: "application/json",
|
|
625
924
|
"x-nextjs-data": "1"
|
|
626
|
-
}
|
|
925
|
+
};
|
|
926
|
+
const deploymentId = getDeploymentId();
|
|
927
|
+
if (deploymentId) headers[NEXT_DEPLOYMENT_ID_HEADER] = deploymentId;
|
|
928
|
+
res = await dedupedPagesDataFetch(initialTarget.dataHref, {
|
|
929
|
+
headers,
|
|
930
|
+
signal: controller.signal
|
|
931
|
+
});
|
|
627
932
|
} catch (err) {
|
|
628
933
|
if (err instanceof DOMException && err.name === "AbortError") throw new NavigationCancelledError(url);
|
|
629
934
|
throw err;
|
|
@@ -634,11 +939,14 @@ async function navigateClientData(url, target, controller, navId, assertStillCur
|
|
|
634
939
|
const redirectedUrl = resolveLocalRedirectUrl(softRedirect);
|
|
635
940
|
if (!redirectedUrl) scheduleHardNavigationAndThrow(softRedirect, "Navigation redirected externally");
|
|
636
941
|
window.history.replaceState(window.history.state ?? {}, "", redirectedUrl);
|
|
637
|
-
|
|
942
|
+
routerRuntimeState.lastPathnameAndSearch = window.location.pathname + window.location.search;
|
|
638
943
|
await navigateClientHtml(redirectedUrl, redirectedUrl, controller, navId, assertStillCurrent);
|
|
639
944
|
return;
|
|
640
945
|
}
|
|
641
946
|
if (!res.ok) scheduleHardNavigationAndThrow(url, `Data navigation failed: ${res.status} ${res.statusText}`);
|
|
947
|
+
const rewriteTarget = res.headers.get("x-nextjs-rewrite");
|
|
948
|
+
const target = rewriteTarget ? resolvePagesDataNavigationTarget(rewriteTarget, __basePath) : initialTarget;
|
|
949
|
+
if (!target) scheduleHardNavigationAndThrow(url, "Data navigation failed: rewrite target has no page loader");
|
|
642
950
|
let body;
|
|
643
951
|
try {
|
|
644
952
|
body = await res.json();
|
|
@@ -646,7 +954,9 @@ async function navigateClientData(url, target, controller, navId, assertStillCur
|
|
|
646
954
|
scheduleHardNavigationAndThrow(url, "Data navigation failed: invalid JSON response");
|
|
647
955
|
}
|
|
648
956
|
assertStillCurrent();
|
|
649
|
-
const
|
|
957
|
+
const props = isUnknownRecord(body) ? body : {};
|
|
958
|
+
const rawPageProps = props.pageProps;
|
|
959
|
+
const pageProps = isUnknownRecord(rawPageProps) ? rawPageProps : {};
|
|
650
960
|
const redirectDestination = pageProps.__N_REDIRECT;
|
|
651
961
|
if (typeof redirectDestination === "string") {
|
|
652
962
|
handleDataRedirect(redirectDestination, pageProps.__N_REDIRECT_BASE_PATH, options.mode);
|
|
@@ -673,17 +983,18 @@ async function navigateClientData(url, target, controller, navId, assertStillCur
|
|
|
673
983
|
assertStillCurrent();
|
|
674
984
|
let element;
|
|
675
985
|
if (AppComponent) element = React.createElement(AppComponent, {
|
|
986
|
+
...props,
|
|
676
987
|
Component: PageComponent,
|
|
677
|
-
pageProps
|
|
988
|
+
pageProps: rawPageProps,
|
|
989
|
+
router: Router
|
|
678
990
|
});
|
|
679
991
|
else element = React.createElement(PageComponent, pageProps);
|
|
680
|
-
element = wrapWithRouterContext(element);
|
|
681
992
|
const mergedQuery = mergeRouteParamsIntoQuery(parseQueryString(target.search), target.params);
|
|
682
993
|
const prev = window.__NEXT_DATA__;
|
|
683
994
|
const nextLocale = (window.__VINEXT_LOCALES__?.length ?? 0) > 0 ? target.locale ?? window.__VINEXT_DEFAULT_LOCALE__ : prev?.locale;
|
|
684
995
|
const nextData = {
|
|
685
996
|
...prev,
|
|
686
|
-
props
|
|
997
|
+
props,
|
|
687
998
|
page: target.pattern,
|
|
688
999
|
query: mergedQuery,
|
|
689
1000
|
buildId: target.buildId,
|
|
@@ -692,7 +1003,8 @@ async function navigateClientData(url, target, controller, navId, assertStillCur
|
|
|
692
1003
|
};
|
|
693
1004
|
window.__NEXT_DATA__ = nextData;
|
|
694
1005
|
applyVinextLocaleGlobals(window, nextData);
|
|
695
|
-
|
|
1006
|
+
await renderPagesRouterElement(element, options.scroll);
|
|
1007
|
+
assertStillCurrent();
|
|
696
1008
|
}
|
|
697
1009
|
/**
|
|
698
1010
|
* Perform client-side navigation by fetching the page's full HTML and
|
|
@@ -707,8 +1019,7 @@ async function navigateClientData(url, target, controller, navId, assertStillCur
|
|
|
707
1019
|
async function navigateClientHtml(url, fetchUrl, controller, navId, assertStillCurrent, options = {}) {
|
|
708
1020
|
let browserUrl = url;
|
|
709
1021
|
let pendingRedirectHistoryUrl = fetchUrl === url ? null : url;
|
|
710
|
-
|
|
711
|
-
if (!root) {
|
|
1022
|
+
if (!window.__VINEXT_ROOT__) {
|
|
712
1023
|
window.location.href = browserUrl;
|
|
713
1024
|
return;
|
|
714
1025
|
}
|
|
@@ -736,7 +1047,9 @@ async function navigateClientHtml(url, fetchUrl, controller, navId, assertStillC
|
|
|
736
1047
|
const nextDataJson = extractVinextNextDataJson(html);
|
|
737
1048
|
if (!nextDataJson) scheduleHardNavigationAndThrow(url, "Navigation failed: missing __NEXT_DATA__ in response");
|
|
738
1049
|
const nextData = parseVinextNextDataJson(nextDataJson);
|
|
739
|
-
const
|
|
1050
|
+
const props = nextData.props && typeof nextData.props === "object" ? nextData.props : {};
|
|
1051
|
+
const rawPageProps = props.pageProps;
|
|
1052
|
+
const pageProps = isUnknownRecord(rawPageProps) ? rawPageProps : {};
|
|
740
1053
|
let pageModuleUrl = nextData.__vinext?.pageModuleUrl;
|
|
741
1054
|
if (!pageModuleUrl) {
|
|
742
1055
|
const moduleMatch = html.match(/import\("([^"]+)"\);\s*\n\s*const PageComponent/);
|
|
@@ -744,11 +1057,10 @@ async function navigateClientHtml(url, fetchUrl, controller, navId, assertStillC
|
|
|
744
1057
|
pageModuleUrl = moduleMatch?.[1] ?? altMatch?.[1] ?? void 0;
|
|
745
1058
|
}
|
|
746
1059
|
let pageModule;
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
} else {
|
|
1060
|
+
const loader = window.__VINEXT_PAGE_LOADERS__?.[nextData.page];
|
|
1061
|
+
if (loader) pageModule = await loader();
|
|
1062
|
+
else if (!pageModuleUrl) scheduleHardNavigationAndThrow(browserUrl, "Navigation failed: no page module URL found");
|
|
1063
|
+
else {
|
|
752
1064
|
if (!isValidModulePath(pageModuleUrl)) {
|
|
753
1065
|
console.error("[vinext] Blocked import of invalid page module path:", pageModuleUrl);
|
|
754
1066
|
scheduleHardNavigationAndThrow(browserUrl, "Navigation failed: invalid page module path");
|
|
@@ -777,18 +1089,20 @@ async function navigateClientHtml(url, fetchUrl, controller, navId, assertStillC
|
|
|
777
1089
|
assertStillCurrent();
|
|
778
1090
|
let element;
|
|
779
1091
|
if (AppComponent) element = React.createElement(AppComponent, {
|
|
1092
|
+
...props,
|
|
780
1093
|
Component: PageComponent,
|
|
781
|
-
pageProps
|
|
1094
|
+
pageProps: rawPageProps,
|
|
1095
|
+
router: Router
|
|
782
1096
|
});
|
|
783
1097
|
else element = React.createElement(PageComponent, pageProps);
|
|
784
|
-
element = wrapWithRouterContext(element);
|
|
785
1098
|
if (pendingRedirectHistoryUrl) {
|
|
786
1099
|
window.history.replaceState(window.history.state ?? {}, "", pendingRedirectHistoryUrl);
|
|
787
|
-
|
|
1100
|
+
routerRuntimeState.lastPathnameAndSearch = window.location.pathname + window.location.search;
|
|
788
1101
|
}
|
|
789
1102
|
window.__NEXT_DATA__ = nextData;
|
|
790
1103
|
applyVinextLocaleGlobals(window, nextData);
|
|
791
|
-
|
|
1104
|
+
await renderPagesRouterElement(element, options.scroll);
|
|
1105
|
+
assertStillCurrent();
|
|
792
1106
|
}
|
|
793
1107
|
/**
|
|
794
1108
|
* Perform client-side navigation. Prefers the JSON data endpoint when the
|
|
@@ -806,43 +1120,50 @@ async function navigateClientHtml(url, fetchUrl, controller, navId, assertStillC
|
|
|
806
1120
|
*/
|
|
807
1121
|
async function navigateClient(url, fetchUrl = url, options = {}) {
|
|
808
1122
|
if (typeof window === "undefined") return;
|
|
809
|
-
|
|
1123
|
+
const previousAbortController = routerRuntimeState.activeAbortController;
|
|
1124
|
+
if (previousAbortController) queueMicrotask(() => previousAbortController.abort());
|
|
1125
|
+
cancelPreviousRenderCommit();
|
|
810
1126
|
const controller = new AbortController();
|
|
811
|
-
|
|
812
|
-
const navId = ++
|
|
1127
|
+
routerRuntimeState.activeAbortController = controller;
|
|
1128
|
+
const navId = ++routerRuntimeState.navigationId;
|
|
813
1129
|
/** Check if this navigation is still the active one. If not, throw. */
|
|
814
1130
|
function assertStillCurrent() {
|
|
815
|
-
if (navId !==
|
|
1131
|
+
if (navId !== routerRuntimeState.navigationId) throw new NavigationCancelledError(url);
|
|
816
1132
|
}
|
|
817
1133
|
try {
|
|
818
1134
|
if (options.allowNotFoundResponse === true) await navigateClientHtml(url, fetchUrl, controller, navId, assertStillCurrent, options);
|
|
819
1135
|
else {
|
|
820
1136
|
let browserUrl = url;
|
|
821
1137
|
let htmlFetchUrl = fetchUrl;
|
|
822
|
-
|
|
1138
|
+
let dataTarget = resolvePagesDataNavigationTarget(browserUrl, __basePath);
|
|
1139
|
+
let middlewareDataResponse;
|
|
823
1140
|
if (!dataTarget) {
|
|
824
|
-
let
|
|
1141
|
+
let middlewareEffect;
|
|
825
1142
|
try {
|
|
826
|
-
|
|
1143
|
+
middlewareEffect = await resolveMiddlewareDataEffect(browserUrl, controller.signal);
|
|
827
1144
|
} catch (err) {
|
|
828
1145
|
if (err instanceof DOMException && err.name === "AbortError") throw new NavigationCancelledError(browserUrl);
|
|
829
1146
|
throw err;
|
|
830
1147
|
}
|
|
831
1148
|
assertStillCurrent();
|
|
1149
|
+
const redirectLocation = middlewareEffect?.redirectLocation ?? null;
|
|
832
1150
|
if (redirectLocation) {
|
|
833
1151
|
const redirectedUrl = resolveLocalRedirectUrl(redirectLocation);
|
|
834
1152
|
if (!redirectedUrl) scheduleHardNavigationAndThrow(redirectLocation, "Navigation redirected externally");
|
|
835
1153
|
window.history.replaceState(window.history.state ?? {}, "", redirectedUrl);
|
|
836
|
-
|
|
1154
|
+
routerRuntimeState.lastPathnameAndSearch = window.location.pathname + window.location.search;
|
|
837
1155
|
browserUrl = redirectedUrl;
|
|
838
1156
|
htmlFetchUrl = redirectedUrl;
|
|
1157
|
+
} else if (middlewareEffect?.rewriteTarget) {
|
|
1158
|
+
dataTarget = resolvePagesDataNavigationTarget(middlewareEffect.rewriteTarget, __basePath);
|
|
1159
|
+
if (dataTarget) middlewareDataResponse = middlewareEffect.response;
|
|
839
1160
|
}
|
|
840
1161
|
}
|
|
841
|
-
if (dataTarget) await navigateClientData(browserUrl, dataTarget, controller, navId, assertStillCurrent, options);
|
|
1162
|
+
if (dataTarget) await navigateClientData(browserUrl, dataTarget, controller, navId, assertStillCurrent, options, middlewareDataResponse);
|
|
842
1163
|
else await navigateClientHtml(browserUrl, htmlFetchUrl, controller, navId, assertStillCurrent, options);
|
|
843
1164
|
}
|
|
844
1165
|
} finally {
|
|
845
|
-
if (navId ===
|
|
1166
|
+
if (navId === routerRuntimeState.navigationId) routerRuntimeState.activeAbortController = null;
|
|
846
1167
|
}
|
|
847
1168
|
}
|
|
848
1169
|
/**
|
|
@@ -928,8 +1249,8 @@ function dispatchNavigateEvent() {
|
|
|
928
1249
|
* locale and the canonical app-relative `as` path.
|
|
929
1250
|
*/
|
|
930
1251
|
function updateHistory(mode, fullUrl, navState) {
|
|
931
|
-
const
|
|
932
|
-
const key = mode === "push" ? createHistoryKey() :
|
|
1252
|
+
const previousKey = getRouterStateKey(window.history.state);
|
|
1253
|
+
const key = mode === "push" ? createHistoryKey() : previousKey ?? routerRuntimeState.currentHistoryKey ?? createHistoryKey();
|
|
933
1254
|
const state = {
|
|
934
1255
|
url: navState?.url ?? fullUrl,
|
|
935
1256
|
as: navState?.as ?? fullUrl,
|
|
@@ -939,13 +1260,13 @@ function updateHistory(mode, fullUrl, navState) {
|
|
|
939
1260
|
};
|
|
940
1261
|
if (mode === "push") window.history.pushState(state, "", fullUrl);
|
|
941
1262
|
else window.history.replaceState(state, "", fullUrl);
|
|
942
|
-
|
|
943
|
-
|
|
1263
|
+
routerRuntimeState.currentHistoryKey = key;
|
|
1264
|
+
routerRuntimeState.lastPathnameAndSearch = window.location.pathname + window.location.search;
|
|
1265
|
+
routerRuntimeState.routerDidNavigate = true;
|
|
944
1266
|
}
|
|
945
|
-
let _historyKeyCounter = 0;
|
|
946
1267
|
function createHistoryKey() {
|
|
947
|
-
|
|
948
|
-
return `vinext_${
|
|
1268
|
+
routerRuntimeState.historyKeyCounter += 1;
|
|
1269
|
+
return `vinext_${routerRuntimeState.historyKeyCounter.toString(36)}_${Math.random().toString(36).slice(2, 9)}`;
|
|
949
1270
|
}
|
|
950
1271
|
/**
|
|
951
1272
|
* Throw the canonical "no router instance" error used when a Pages Router
|
|
@@ -979,7 +1300,8 @@ async function performNavigation(url, as, options, mode, onStateUpdate) {
|
|
|
979
1300
|
assertSafeNavigationUrl(resolveUrl(url));
|
|
980
1301
|
if (as !== void 0) assertSafeNavigationUrl(String(as));
|
|
981
1302
|
const navigationLocale = resolveTransitionLocale(options?.locale);
|
|
982
|
-
let resolved = resolveNavigationTarget(url, as, navigationLocale);
|
|
1303
|
+
let resolved = resolveNavigationTarget(url, as, navigationLocale, as === void 0 && options?.locale !== void 0 && typeof url !== "string" && url.pathname === void 0 && (url.query !== void 0 && Object.keys(url.query).length > 0 || typeof url.search === "string" && url.search.length > 0 || typeof url.hash === "string" && url.hash.length > 0));
|
|
1304
|
+
if (as === void 0 && (typeof url === "string" && options?._vinextInterpolateDynamicRoute === true || typeof url !== "string" && url.pathname === void 0 && (url.query !== void 0 && Object.keys(url.query).length > 0 || typeof url.search === "string" && url.search.length > 0))) resolved = interpolateCurrentDynamicRoute(resolved);
|
|
983
1305
|
if (isExternalUrl(resolved)) {
|
|
984
1306
|
const localPath = toSameOriginAppPath(resolved, __basePath);
|
|
985
1307
|
if (localPath == null) {
|
|
@@ -993,12 +1315,21 @@ async function performNavigation(url, as, options, mode, onStateUpdate) {
|
|
|
993
1315
|
const full = normalizePathTrailingSlash(toBrowserNavigationHref(resolved, window.location.href, __basePath), __trailingSlash);
|
|
994
1316
|
const errorRouteHtmlFetchUrl = resolvePagesErrorHtmlFetchUrl(url, navigationLocale);
|
|
995
1317
|
const htmlFetchUrl = errorRouteHtmlFetchUrl ?? getPagesHtmlFetchUrl(full, navigationLocale);
|
|
996
|
-
const navigateOptions = errorRouteHtmlFetchUrl ? {
|
|
997
|
-
allowNotFoundResponse: true,
|
|
998
|
-
mode
|
|
999
|
-
} : { mode };
|
|
1000
1318
|
const shallow = options?.shallow ?? false;
|
|
1001
1319
|
const doScroll = options?.scroll !== false;
|
|
1320
|
+
const hash = extractHash(resolved);
|
|
1321
|
+
const scrollTarget = doScroll ? {
|
|
1322
|
+
x: 0,
|
|
1323
|
+
y: 0
|
|
1324
|
+
} : null;
|
|
1325
|
+
const navigateOptions = errorRouteHtmlFetchUrl ? {
|
|
1326
|
+
allowNotFoundResponse: true,
|
|
1327
|
+
mode,
|
|
1328
|
+
scroll: scrollTarget
|
|
1329
|
+
} : {
|
|
1330
|
+
mode,
|
|
1331
|
+
scroll: scrollTarget
|
|
1332
|
+
};
|
|
1002
1333
|
const navStateOptions = { shallow };
|
|
1003
1334
|
if (navigationLocale !== void 0) navStateOptions.locale = navigationLocale;
|
|
1004
1335
|
const resolvedNoHash = stripHash(resolved);
|
|
@@ -1007,7 +1338,8 @@ async function performNavigation(url, as, options, mode, onStateUpdate) {
|
|
|
1007
1338
|
as: resolvedNoHash,
|
|
1008
1339
|
options: navStateOptions
|
|
1009
1340
|
};
|
|
1010
|
-
if (isHashOnlyChange(full)) {
|
|
1341
|
+
if (options?._h !== 1 && isHashOnlyChange(full)) {
|
|
1342
|
+
if (mode === "push") saveScrollPosition();
|
|
1011
1343
|
const eventUrl = resolveHashUrl(full);
|
|
1012
1344
|
routerEvents.emit("hashChangeStart", eventUrl, { shallow });
|
|
1013
1345
|
updateHistory(mode, resolved.startsWith("#") ? resolved : full, navState);
|
|
@@ -1020,25 +1352,25 @@ async function performNavigation(url, as, options, mode, onStateUpdate) {
|
|
|
1020
1352
|
const appPath = getLocalPathname(resolved);
|
|
1021
1353
|
const appPathNorm = appPath !== null ? removeTrailingSlash(appPath) : null;
|
|
1022
1354
|
const appPathEntry = appPathNorm !== null ? getPagesRouterComponentsMap()[appPathNorm] : void 0;
|
|
1023
|
-
if (appPathEntry !== void 0 && "__appRouter" in appPathEntry && appPathEntry.__appRouter) {
|
|
1355
|
+
if (appPathEntry !== void 0 && "__appRouter" in appPathEntry && appPathEntry.__appRouter || ["app", "document"].includes(resolveHybridClientRouteOwner(resolved, __basePath) ?? "")) {
|
|
1024
1356
|
if (mode === "push") window.location.assign(full);
|
|
1025
1357
|
else window.location.replace(full);
|
|
1026
1358
|
return new Promise(() => {});
|
|
1027
1359
|
}
|
|
1028
1360
|
if (mode === "push") saveScrollPosition();
|
|
1029
|
-
|
|
1361
|
+
const isQueryUpdating = options?._h === 1;
|
|
1362
|
+
if (!isQueryUpdating) routerEvents.emit("routeChangeStart", resolved, { shallow });
|
|
1030
1363
|
routerEvents.emit("beforeHistoryChange", resolved, { shallow });
|
|
1031
1364
|
updateHistory(mode, full, navState);
|
|
1032
1365
|
if (!shallow) {
|
|
1033
1366
|
const result = await runNavigateClient(full, resolved, htmlFetchUrl, navigateOptions);
|
|
1034
1367
|
if (result === "cancelled") return true;
|
|
1035
1368
|
if (result === "failed") return false;
|
|
1036
|
-
}
|
|
1037
|
-
onStateUpdate?.();
|
|
1038
|
-
routerEvents.emit("routeChangeComplete", resolved, { shallow });
|
|
1039
|
-
const hash = extractHash(resolved);
|
|
1040
|
-
if (doScroll) if (hash) scrollToHashTarget(hash);
|
|
1369
|
+
} else if (doScroll) if (hash) scrollToHashTarget(hash);
|
|
1041
1370
|
else window.scrollTo(0, 0);
|
|
1371
|
+
onStateUpdate?.();
|
|
1372
|
+
if (!isQueryUpdating) routerEvents.emit("routeChangeComplete", resolved, { shallow });
|
|
1373
|
+
if (doScroll && hash && !shallow) scrollToHashTarget(hash);
|
|
1042
1374
|
dispatchNavigateEvent();
|
|
1043
1375
|
return true;
|
|
1044
1376
|
}
|
|
@@ -1083,8 +1415,9 @@ async function prefetchUrl(url) {
|
|
|
1083
1415
|
*/
|
|
1084
1416
|
function useRouter() {
|
|
1085
1417
|
const router = useContext(RouterContext);
|
|
1086
|
-
if (
|
|
1087
|
-
return
|
|
1418
|
+
if (router) return router;
|
|
1419
|
+
if (typeof window !== "undefined" && window.__VINEXT_PAGE_LOADERS__ !== void 0) return Router;
|
|
1420
|
+
throw new Error("NextRouter was not mounted. https://nextjs.org/docs/messages/next-router-not-mounted");
|
|
1088
1421
|
}
|
|
1089
1422
|
function PagesRouterProvider({ children }) {
|
|
1090
1423
|
const [{ pathname, query, asPath, isReady }, setState] = useState(getRouterSnapshot);
|
|
@@ -1095,9 +1428,11 @@ function PagesRouterProvider({ children }) {
|
|
|
1095
1428
|
window.addEventListener("vinext:navigate", onNavigate);
|
|
1096
1429
|
let cancelled = false;
|
|
1097
1430
|
const readyTimer = window.setTimeout(() => {
|
|
1098
|
-
if (cancelled
|
|
1099
|
-
|
|
1100
|
-
|
|
1431
|
+
if (cancelled) return;
|
|
1432
|
+
if (markPagesRouterReady()) {
|
|
1433
|
+
setState(getRouterSnapshot());
|
|
1434
|
+
notifyNextNavigationPagesContext();
|
|
1435
|
+
}
|
|
1101
1436
|
}, 0);
|
|
1102
1437
|
return () => {
|
|
1103
1438
|
cancelled = true;
|
|
@@ -1140,36 +1475,47 @@ function PagesRouterProvider({ children }) {
|
|
|
1140
1475
|
Router.prefetch(href);
|
|
1141
1476
|
}
|
|
1142
1477
|
}), []);
|
|
1143
|
-
const content = createElement(RouterContext.Provider, { value: router }, children);
|
|
1478
|
+
const content = createElement(RouterContext.Provider, { value: router }, createElement(Fragment, null, children, createElement(PagesRouterHydrationMarker)));
|
|
1144
1479
|
return AppRouterContext ? createElement(AppRouterContext.Provider, { value: appRouter }, content) : content;
|
|
1145
1480
|
}
|
|
1146
|
-
let _beforePopStateCb;
|
|
1147
|
-
let _lastPathnameAndSearch = typeof window !== "undefined" ? window.location.pathname + window.location.search : "";
|
|
1148
|
-
let _isFirstPopStateEvent = true;
|
|
1149
|
-
let _routerDidNavigate = false;
|
|
1150
1481
|
function isNextRouterState(state) {
|
|
1151
1482
|
return typeof state === "object" && state !== null && "__N" in state && state.__N === true;
|
|
1152
1483
|
}
|
|
1484
|
+
function getRouterStateKey(state) {
|
|
1485
|
+
if (!isNextRouterState(state)) return void 0;
|
|
1486
|
+
return typeof state.key === "string" ? state.key : void 0;
|
|
1487
|
+
}
|
|
1153
1488
|
function handlePagesRouterPopState(e) {
|
|
1154
1489
|
const browserUrl = window.location.pathname + window.location.search;
|
|
1155
1490
|
const appUrl = stripBasePath(window.location.pathname, __basePath) + window.location.search;
|
|
1156
1491
|
const state = e.state;
|
|
1157
|
-
const wasFirst =
|
|
1158
|
-
|
|
1492
|
+
const wasFirst = routerRuntimeState.isFirstPopStateEvent;
|
|
1493
|
+
routerRuntimeState.isFirstPopStateEvent = false;
|
|
1159
1494
|
if (state !== null && state !== void 0 && !isNextRouterState(state)) return;
|
|
1160
|
-
if (wasFirst && !
|
|
1495
|
+
if (wasFirst && !routerRuntimeState.routerDidNavigate && isNextRouterState(state)) {
|
|
1161
1496
|
const currentLocale = window.__VINEXT_LOCALE__;
|
|
1162
|
-
if (state.options?.locale === currentLocale && typeof state.as === "string" && withBasePath(state.as, __basePath) ===
|
|
1497
|
+
if (state.options?.locale === currentLocale && typeof state.as === "string" && withBasePath(state.as, __basePath) === routerRuntimeState.lastPathnameAndSearch) return;
|
|
1498
|
+
}
|
|
1499
|
+
const isHashOnly = browserUrl === routerRuntimeState.lastPathnameAndSearch;
|
|
1500
|
+
const targetKey = getRouterStateKey(state);
|
|
1501
|
+
let forcedScroll;
|
|
1502
|
+
if (manualScrollRestoration) {
|
|
1503
|
+
const currentKey = routerRuntimeState.currentHistoryKey;
|
|
1504
|
+
if (currentKey !== void 0 && currentKey !== targetKey) saveScrollPositionToSessionStorage(currentKey, getWindowScrollPosition());
|
|
1505
|
+
if (targetKey !== void 0 && currentKey !== targetKey) forcedScroll = readScrollPositionFromSessionStorage(targetKey) ?? {
|
|
1506
|
+
x: 0,
|
|
1507
|
+
y: 0
|
|
1508
|
+
};
|
|
1163
1509
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
if (!_beforePopStateCb({
|
|
1510
|
+
if (routerRuntimeState.beforePopStateCb !== void 0) {
|
|
1511
|
+
if (!routerRuntimeState.beforePopStateCb({
|
|
1167
1512
|
url: appUrl,
|
|
1168
1513
|
as: appUrl,
|
|
1169
1514
|
options: { shallow: false }
|
|
1170
1515
|
})) return;
|
|
1171
1516
|
}
|
|
1172
|
-
|
|
1517
|
+
if (targetKey !== void 0) routerRuntimeState.currentHistoryKey = targetKey;
|
|
1518
|
+
routerRuntimeState.lastPathnameAndSearch = browserUrl;
|
|
1173
1519
|
if (isHashOnly) {
|
|
1174
1520
|
const hashUrl = appUrl + window.location.hash;
|
|
1175
1521
|
routerEvents.emit("hashChangeStart", hashUrl, { shallow: false });
|
|
@@ -1183,9 +1529,12 @@ function handlePagesRouterPopState(e) {
|
|
|
1183
1529
|
routerEvents.emit("routeChangeStart", fullAppUrl, { shallow: false });
|
|
1184
1530
|
routerEvents.emit("beforeHistoryChange", fullAppUrl, { shallow: false });
|
|
1185
1531
|
(async () => {
|
|
1186
|
-
|
|
1532
|
+
const scrollTarget = manualScrollRestoration ? forcedScroll ?? readScrollPosition(state) ?? {
|
|
1533
|
+
x: 0,
|
|
1534
|
+
y: 0
|
|
1535
|
+
} : readScrollPosition(state);
|
|
1536
|
+
if (await runNavigateClient(browserUrl, fullAppUrl, getPagesHtmlFetchUrl(browserUrl, effectiveLocale), { scroll: scrollTarget }) === "completed") {
|
|
1187
1537
|
routerEvents.emit("routeChangeComplete", fullAppUrl, { shallow: false });
|
|
1188
|
-
restoreScrollPosition(e.state);
|
|
1189
1538
|
dispatchNavigateEvent();
|
|
1190
1539
|
}
|
|
1191
1540
|
})();
|
|
@@ -1198,9 +1547,22 @@ setPagesRouterPopStateHandler(handlePagesRouterPopState);
|
|
|
1198
1547
|
* The provider owns the reactive Pages Router snapshot so next/router and
|
|
1199
1548
|
* next/compat/router consumers share one context value instead of each hook
|
|
1200
1549
|
* installing its own global URL-change listener.
|
|
1550
|
+
*
|
|
1551
|
+
* The PagesRouterCommitBoundary exists for client navigations: its layout
|
|
1552
|
+
* callback runs scroll restoration at commit time and resolves the navigation
|
|
1553
|
+
* at the same root-commit boundary Next.js awaits before routeChangeComplete.
|
|
1554
|
+
* Its onError rejection drives the hard-navigation fallback in runNavigateClient.
|
|
1555
|
+
* The same boundary intentionally also wraps SSR and initial hydration, where
|
|
1556
|
+
* callbacks default to noopCommit: a hydration-time render error is caught
|
|
1557
|
+
* here (React still console.error's it) instead of propagating, matching the
|
|
1558
|
+
* navigation-path containment.
|
|
1201
1559
|
*/
|
|
1202
|
-
function wrapWithRouterContext(element) {
|
|
1203
|
-
|
|
1560
|
+
function wrapWithRouterContext(element, onCommit = noopCommit, onError = noopCommit) {
|
|
1561
|
+
const { CommitBoundary, Provider } = getPagesRouterRuntimeComponents();
|
|
1562
|
+
return createElement(CommitBoundary, {
|
|
1563
|
+
onCommit,
|
|
1564
|
+
onError
|
|
1565
|
+
}, createElement(Provider, null, element));
|
|
1204
1566
|
}
|
|
1205
1567
|
/**
|
|
1206
1568
|
* Higher-order component that injects the Pages Router `router` instance as
|
|
@@ -1263,7 +1625,7 @@ const RouterMethods = {
|
|
|
1263
1625
|
},
|
|
1264
1626
|
beforePopState: (cb) => {
|
|
1265
1627
|
if (typeof window === "undefined") throwNoRouterInstance();
|
|
1266
|
-
|
|
1628
|
+
routerRuntimeState.beforePopStateCb = cb;
|
|
1267
1629
|
},
|
|
1268
1630
|
events: routerEvents
|
|
1269
1631
|
};
|
|
@@ -1330,7 +1692,7 @@ const Router = Object.defineProperties(RouterMethods, {
|
|
|
1330
1692
|
isReady: {
|
|
1331
1693
|
enumerable: true,
|
|
1332
1694
|
get() {
|
|
1333
|
-
return isPagesRouterReady();
|
|
1695
|
+
return isPagesRouterReady() && (typeof window === "undefined" || window.__NEXT_HYDRATED === true);
|
|
1334
1696
|
}
|
|
1335
1697
|
},
|
|
1336
1698
|
isPreview: {
|
|
@@ -1346,27 +1708,35 @@ const Router = Object.defineProperties(RouterMethods, {
|
|
|
1346
1708
|
}
|
|
1347
1709
|
}
|
|
1348
1710
|
});
|
|
1349
|
-
|
|
1711
|
+
routerRuntimeState.publicRouter = Router;
|
|
1712
|
+
const deprecatedRouterEvents = [
|
|
1350
1713
|
"routeChangeStart",
|
|
1351
1714
|
"beforeHistoryChange",
|
|
1352
1715
|
"routeChangeComplete",
|
|
1353
1716
|
"routeChangeError",
|
|
1354
1717
|
"hashChangeStart",
|
|
1355
1718
|
"hashChangeComplete"
|
|
1356
|
-
]
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1719
|
+
];
|
|
1720
|
+
if (!routerRuntimeState.deprecatedEventBridgeInstalled) {
|
|
1721
|
+
routerRuntimeState.deprecatedEventBridgeInstalled = true;
|
|
1722
|
+
for (const event of deprecatedRouterEvents) {
|
|
1723
|
+
const eventField = `on${event.charAt(0).toUpperCase()}${event.substring(1)}`;
|
|
1724
|
+
routerEvents.on(event, (...args) => {
|
|
1725
|
+
const handler = (routerRuntimeState.publicRouter ?? Router)[eventField];
|
|
1726
|
+
if (typeof handler === "function") try {
|
|
1727
|
+
handler(...args);
|
|
1728
|
+
} catch (err) {
|
|
1729
|
+
console.error(`Error when running the Router event: ${eventField}`);
|
|
1730
|
+
console.error(err instanceof Error ? `${err.message}\n${err.stack}` : String(err));
|
|
1731
|
+
}
|
|
1732
|
+
});
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
if (typeof window !== "undefined") {
|
|
1736
|
+
installPagesRouterRuntime();
|
|
1737
|
+
installWindowNext({ router: Router });
|
|
1367
1738
|
}
|
|
1368
|
-
if (typeof window !== "undefined") installWindowNext({ router: Router });
|
|
1369
1739
|
const _PAGES_NAVIGATION_ACCESSOR_KEY = Symbol.for("vinext.navigation.pagesNavigationContextAccessor");
|
|
1370
1740
|
globalThis[_PAGES_NAVIGATION_ACCESSOR_KEY] = getPagesNavigationContext;
|
|
1371
1741
|
//#endregion
|
|
1372
|
-
export { _registerRouterStateAccessors, applyNavigationLocale, Router as default, getPagesNavigationContext, getPagesNavigationIsReadyFromSerializedState, isExternalUrl, isHashOnlyChange, setSSRContext, useRouter, withRouter, wrapWithRouterContext };
|
|
1742
|
+
export { initializePagesRouterReadyFromNextData as _initializePagesRouterReadyFromNextData, markPagesRouterReady as _markPagesRouterReady, _registerRouterStateAccessors, applyNavigationLocale, Router as default, getPagesNavigationContext, getPagesNavigationIsReadyFromSerializedState, isExternalUrl, isHashOnlyChange, setSSRContext, useRouter, withRouter, wrapWithRouterContext };
|