next
Version:
The React Framework
121 lines (120 loc) • 5.34 kB
JavaScript
// The sequential-router-queue implementation of the navigator interface
// (navigator.ts). Callers must never import this module directly; they import
// './navigator', which resolves here unless `experimental.
// concurrentRouterQueue` swaps in `./concurrent-router-queue` at the bundler
// level (see create-compiler-aliases.ts and next_import_map.rs).
//
// The legacy reducer action objects are an implementation detail of the
// sequential action queue; they are constructed here and never by callers.
//
// This module must remain free of side effects at module scope: in addition
// to the browser bundle, a statically-resolved copy is compiled into the
// pre-compiled app-page runtime bundles (via app-render.tsx), where the
// bundler alias cannot reach. Only the browser copy's operations ever run.
import { addTransitionType, startTransition } from 'react';
import { ACTION_HMR_REFRESH, ACTION_NAVIGATE, ACTION_REFRESH, ACTION_RESTORE, ScrollBehavior } from './router-reducer/router-reducer-types';
import { dispatchAppRouterAction } from './use-action-queue';
import { getCurrentAppRouterState } from './app-router-instance';
import { setLinkForCurrentNavigation } from './links';
import { startRouterTransition } from './router-transition';
import { addBasePath } from '../add-base-path';
import { isExternalURL } from './app-router-utils';
import { isJavaScriptURLString } from '../lib/javascript-url';
import { resetKnownRoutes } from './segment-cache/optimistic-routes';
function getRequiredAppRouterState() {
const state = getCurrentAppRouterState();
if (state === null) {
throw new Error('Internal Next.js error: Router action dispatched before initialization.');
}
return state;
}
export function navigate(href, navigateType, scrollBehavior, linkInstanceRef, transitionTypes, prefetchIntent) {
if (isJavaScriptURLString(href)) {
throw new Error('Next.js has blocked a javascript: URL as a security precaution.');
}
startTransition(()=>{
// TODO: This stuff could just go into the reducer. Leaving as-is for now
// since we're about to rewrite all the router reducer stuff anyway.
if (transitionTypes) {
for (const type of transitionTypes){
addTransitionType(type);
}
}
const url = new URL(addBasePath(href), location.href);
if (process.env.__NEXT_APP_NAV_FAIL_HANDLING) {
window.next.__pendingUrl = url;
}
setLinkForCurrentNavigation(linkInstanceRef);
startRouterTransition(href, navigateType, getRequiredAppRouterState().tree, prefetchIntent);
dispatchAppRouterAction({
type: ACTION_NAVIGATE,
url,
isExternalUrl: isExternalURL(url),
locationSearch: location.search,
scrollBehavior,
navigateType
});
});
}
export function push(href, options) {
navigate(href, 'push', options?.scroll === false ? ScrollBehavior.NoScroll : ScrollBehavior.Default, null, options?.transitionTypes, null);
}
export function replace(href, options) {
navigate(href, 'replace', options?.scroll === false ? ScrollBehavior.NoScroll : ScrollBehavior.Default, null, options?.transitionTypes, null);
}
export function traverse(href, historyState) {
startTransition(()=>{
startRouterTransition(href, 'traverse', getRequiredAppRouterState().tree, null);
restore(new URL(href), historyState);
});
}
/**
* Sync the router state to a history entry that was written by something
* other than a router navigation (a userland pushState/replaceState, or a
* bfcache restore). Unlike a traversal, this does not represent a transition
* between routes.
*/ export function restore(url, historyState) {
startTransition(()=>{
dispatchAppRouterAction({
type: ACTION_RESTORE,
url,
historyState
});
});
}
export function refresh() {
startTransition(()=>{
dispatchAppRouterAction({
type: ACTION_REFRESH
});
});
}
// Tracks the newest HMR refresh generation so that a newer refresh can abort
// the request of the one it supersedes. Development only.
let activeHmrRefreshController = null;
// Development only.
export function hmrRefresh() {
if (process.env.NODE_ENV !== 'development') {
throw new Error('hmrRefresh can only be used in development mode. Please use refresh instead.');
} else {
// Reset the known routes table so that route predictions are cleared
// when routes change during development.
resetKnownRoutes();
let signal;
if (process.env.__NEXT_SERVER_COMPONENTS_HMR_CANCELLATION) {
// Abort the superseded generation before scheduling the new one, so its
// request is torn down as early as possible. Halting (not rejecting)
// makes the abort safe regardless of order.
activeHmrRefreshController?.abort();
activeHmrRefreshController = new AbortController();
signal = activeHmrRefreshController.signal;
}
startTransition(()=>{
dispatchAppRouterAction({
type: ACTION_HMR_REFRESH,
signal
});
});
}
}
//# sourceMappingURL=sequential-router-queue.js.map