@tanstack/solid-router
Version:
Modern and scalable routing for Solid applications
132 lines (127 loc) • 5.58 kB
text/typescript
import * as Solid from 'solid-js'
import { RouterCore } from '@tanstack/router-core'
import { isServer } from '@tanstack/router-core/isServer'
import { getStoreFactory } from './routerStores'
import { primeRouterFromRegistry } from './registryTransfer'
import { noteRequest, releaseRequest } from './observe'
import type { RouterHistory } from '@tanstack/history'
import type {
AnyRoute,
CreateRouterFn,
RouterConstructorOptions,
TrailingSlashOption,
} from '@tanstack/router-core'
import type {
ErrorRouteComponent,
NotFoundRouteComponent,
RouteComponent,
} from './route'
import type { JSX } from '@solidjs/web'
declare module '@tanstack/router-core' {
export interface RouterOptionsExtensions {
/**
* The default `component` a route should use if no component is provided.
*
* @default Outlet
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/solid/api/router/RouterOptionsType#defaultcomponent-property)
*/
defaultComponent?: RouteComponent
/**
* The default `errorComponent` a route should use if no error component is provided.
*
* @default ErrorComponent
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/solid/api/router/RouterOptionsType#defaulterrorcomponent-property)
* @link [Guide](https://tanstack.com/router/latest/docs/framework/solid/guide/data-loading#handling-errors-with-routeoptionserrorcomponent)
*/
defaultErrorComponent?: ErrorRouteComponent
/**
* The default `pendingComponent` a route should use if no pending component is provided.
*
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/solid/api/router/RouterOptionsType#defaultpendingcomponent-property)
* @link [Guide](https://tanstack.com/router/latest/docs/framework/solid/guide/data-loading#showing-a-pending-component)
*/
defaultPendingComponent?: RouteComponent
/**
* The default `notFoundComponent` a route should use if no notFound component is provided.
*
* @default NotFound
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/solid/api/router/RouterOptionsType#defaultnotfoundcomponent-property)
* @link [Guide](https://tanstack.com/router/latest/docs/framework/solid/guide/not-found-errors#default-router-wide-not-found-handling)
*/
defaultNotFoundComponent?: NotFoundRouteComponent
/**
* A component that will be used to wrap the entire router.
*
* This is useful for providing a context to the entire router.
*
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/solid/api/router/RouterOptionsType#wrap-property)
*/
Wrap?: (props: { children: any }) => JSX.Element
/**
* A component that will be used to wrap the inner contents of the router.
*
* This is useful for providing a context to the inner contents of the router where you also need access to the router context and hooks.
*
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/solid/api/router/RouterOptionsType#innerwrap-property)
*/
InnerWrap?: (props: { children: any }) => JSX.Element
/**
* The default `onCatch` handler for errors caught by the Router ErrorBoundary
*
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultoncatch-property)
* @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#handling-errors-with-routeoptionsoncatch)
*/
defaultOnCatch?: (error: Error) => void
}
}
export const createRouter: CreateRouterFn = (options) => {
return new Router(options)
}
export class Router<
in out TRouteTree extends AnyRoute,
in out TTrailingSlashOption extends TrailingSlashOption = 'never',
in out TDefaultStructuralSharingOption extends boolean = false,
in out TRouterHistory extends RouterHistory = RouterHistory,
in out TDehydrated extends Record<string, any> = Record<string, any>,
> extends RouterCore<
TRouteTree,
TTrailingSlashOption,
TDefaultStructuralSharingOption,
TRouterHistory,
TDehydrated
> {
constructor(
options: RouterConstructorOptions<
TRouteTree,
TTrailingSlashOption,
TDefaultStructuralSharingOption,
TRouterHistory,
TDehydrated
>,
) {
super(options, getStoreFactory)
// The hydration-claiming boot (see registryTransfer). Router creation is
// the client's natural pre-render moment: module code runs after the
// document — and the registry entries the server's RouterProvider wrote —
// have parsed, and always before hydrate(). Committing here keeps every
// store write outside the hydration render, where it would desync the
// claiming walk. Inert without entries: an SPA page has no registry, and
// a Start app transfers through its own channel (`router.serverSsr`),
// so the first missing entry falls through to unchanged behavior.
if (!(isServer ?? this.isServer)) {
primeRouterFromRegistry(this)
// Solid's observe tier dates a navigation from its request and joins
// it to the interaction it was requested in, both gone by the time a
// blocked history notifies (see `noteRequest`).
if (Solid.OBSERVE !== undefined) {
const commitLocation = this.commitLocation
this.commitLocation = (opts) => {
noteRequest(this)
const committed = commitLocation(opts)
releaseRequest(this)
return committed
}
}
}
}
}