one
Version:
One is a new React Framework that makes Vite serve both native and web.
104 lines (84 loc) • 3.09 kB
text/typescript
import { isWebClient } from '../constants'
import type { OneRouter } from '../interfaces/router'
import { evictOldest } from '../utils/evictOldest'
import {
getLinkingConfig as createLinkingConfig,
type OneLinkingOptions,
} from './getLinkingConfig'
import type { RouteNode } from './Route'
let linkingConfig: OneLinkingOptions | undefined
// cache the base linking config (route-tree dependent, not URL-dependent)
let cachedBaseLinkingConfig: OneLinkingOptions | undefined
let cachedRouteNodeForLinking: RouteNode | null = null
// cache getStateFromPath results by path for SSR performance
// same path always produces the same navigation state (route tree is static in prod)
const ssrStateCache = new Map<string, OneRouter.ResultState | undefined>()
export function getLinking() {
return linkingConfig
}
export function setLinking(_: OneLinkingOptions) {
linkingConfig = _
}
export function resetLinking() {
linkingConfig = undefined
}
/**
* Ensure the base linking config is initialized for a given route tree.
* Does not set any per-request state.
*/
export function ensureBaseLinkingConfig(routeNode: RouteNode | null) {
if (
routeNode &&
(routeNode !== cachedRouteNodeForLinking || !cachedBaseLinkingConfig)
) {
cachedBaseLinkingConfig = createLinkingConfig(routeNode)
cachedRouteNodeForLinking = routeNode
}
}
/**
* Compute initialState from a URL path, with caching for SSR.
* Does not modify the global linkingConfig.
*/
export function getSSRInitialState(
routeNode: RouteNode | null,
initialLocation: URL
): OneRouter.ResultState | undefined {
if (!routeNode) return undefined
ensureBaseLinkingConfig(routeNode)
if (!cachedBaseLinkingConfig) return undefined
const path = initialLocation.pathname + (initialLocation.search || '')
if (ssrStateCache.has(path)) return ssrStateCache.get(path)
const state = cachedBaseLinkingConfig.getStateFromPath?.(
path,
cachedBaseLinkingConfig.config
)
evictOldest(ssrStateCache, 5000, 1000)
ssrStateCache.set(path, state)
return state
}
export function setupLinking(
routeNode: RouteNode | null,
initialLocation?: URL
): OneRouter.ResultState | undefined {
let initialState: OneRouter.ResultState | undefined
if (routeNode) {
// reuse ensureBaseLinkingConfig to avoid duplicating cache logic
ensureBaseLinkingConfig(routeNode)
// shallow copy so per-request mutations (getInitialURL) don't affect cache
linkingConfig = { ...cachedBaseLinkingConfig! }
if (initialLocation) {
linkingConfig.getInitialURL = () => initialLocation.toString()
let path = initialLocation.pathname + (initialLocation.search || '')
if (isWebClient) {
const historyState = window.history.state
if (historyState?.__tempLocation?.pathname && !historyState.__tempKey) {
path =
historyState.__tempLocation.pathname +
(historyState.__tempLocation.search || '')
}
}
initialState = linkingConfig.getStateFromPath?.(path, linkingConfig.config)
}
}
return initialState
}