11import type { Route } from '@rspress/shared' ;
22import {
33 createBrowserRouter ,
4+ Outlet ,
45 RouterProvider ,
56 type StaticHandlerContext ,
67 useLocation ,
@@ -23,17 +24,25 @@ import { removeBase } from './utils';
2324
2425declare global {
2526 interface Window {
26- __RSPRESS_DEBUG_PAGE_DATA__ ?: unknown ;
27+ __RSPRESS_DEBUG_ROUTER__ ?: unknown ;
2728 }
2829}
2930
31+ function getCanonicalRoutePath ( pathname : string ) {
32+ const routePath = removeBase ( pathname ) ;
33+ if ( routePath === '/404' ) {
34+ return '/404' ;
35+ }
36+ return pathnameToRouteService ( routePath ) ?. path || routePath ;
37+ }
38+
3039function AppShell ( ) {
3140 const matches = useMatches ( ) ;
3241 const currentMatch = matches [ matches . length - 1 ] ;
3342 const pageData = currentMatch ?. data as Page | undefined ;
3443
3544 if ( typeof window !== 'undefined' ) {
36- window . __RSPRESS_DEBUG_PAGE_DATA__ = {
45+ window . __RSPRESS_DEBUG_ROUTER__ = {
3746 matches : matches . map ( match => ( {
3847 id : match . id ,
3948 pathname : match . pathname ,
@@ -48,8 +57,8 @@ function AppShell() {
4857 data : currentMatch . data ,
4958 }
5059 : null ,
51- pageData,
5260 } ;
61+ console . warn ( '[rspress-debug-router]' , window . __RSPRESS_DEBUG_ROUTER__ ) ;
5362 }
5463
5564 return (
@@ -61,11 +70,15 @@ function AppShell() {
6170
6271function AliasRouteElement ( ) {
6372 const { pathname } = useLocation ( ) ;
64- const matchedRoute = pathnameToRouteService ( pathname ) ;
73+ const matchedRoute = pathnameToRouteService ( getCanonicalRoutePath ( pathname ) ) ;
6574
6675 return matchedRoute ?. element ?? null ;
6776}
6877
78+ function CanonicalRouteOutlet ( ) {
79+ return < Outlet /> ;
80+ }
81+
6982function toRouteObject ( route : Route , index : number ) {
7083 return {
7184 id : `rspress-route-${ index } ` ,
@@ -75,18 +88,108 @@ function toRouteObject(route: Route, index: number) {
7588 } ;
7689}
7790
91+ function splitRoutes ( routes : Route [ ] ) {
92+ const homeRoute = routes . find ( route => route . path === '/' ) ;
93+ const notFoundRoute = routes . find ( route => route . path === '/404' ) ;
94+ const docRoutes = routes . filter (
95+ route => route . path !== '/' && route . path !== '/404' ,
96+ ) ;
97+
98+ return {
99+ docRoutes,
100+ homeRoute,
101+ notFoundRoute,
102+ } ;
103+ }
104+
105+ function createDataRoutes ( routes : Route [ ] ) {
106+ const { docRoutes, homeRoute, notFoundRoute } = splitRoutes ( routes ) ;
107+ const canonicalRoutes = [
108+ ...docRoutes . map ( ( route , index ) => ( {
109+ id : `rspress-route-${ index } ` ,
110+ path : route . path ,
111+ loader : route . loader ,
112+ } ) ) ,
113+ ...( notFoundRoute
114+ ? [
115+ {
116+ id : 'rspress-route-404' ,
117+ path : '404' ,
118+ loader : notFoundRoute . loader ,
119+ } ,
120+ ]
121+ : [ ] ) ,
122+ ...( homeRoute
123+ ? [
124+ {
125+ id : 'rspress-route-home' ,
126+ index : true ,
127+ loader : homeRoute . loader ,
128+ } ,
129+ ]
130+ : [ ] ) ,
131+ ] ;
132+
133+ return [
134+ {
135+ id : 'rspress-app-shell' ,
136+ path : '/' ,
137+ children : [
138+ {
139+ id : 'rspress-route-canonical' ,
140+ children : canonicalRoutes ,
141+ } ,
142+ {
143+ id : 'rspress-route-alias' ,
144+ path : '*' ,
145+ loader : ( { request } : { request : Request } ) =>
146+ initPageData ( getCanonicalRoutePath ( new URL ( request . url ) . pathname ) ) ,
147+ } ,
148+ ] ,
149+ } ,
150+ ] ;
151+ }
152+
78153function createAppShellRoute ( routes : Route [ ] ) {
154+ const { docRoutes, homeRoute, notFoundRoute } = splitRoutes ( routes ) ;
155+ const canonicalRoutes = [
156+ ...docRoutes . map ( ( route , index ) => toRouteObject ( route , index ) ) ,
157+ ...( notFoundRoute
158+ ? [
159+ {
160+ ...toRouteObject ( notFoundRoute , routes . indexOf ( notFoundRoute ) ) ,
161+ id : 'rspress-route-404' ,
162+ path : '404' ,
163+ } ,
164+ ]
165+ : [ ] ) ,
166+ ...( homeRoute
167+ ? [
168+ {
169+ ...toRouteObject ( homeRoute , routes . indexOf ( homeRoute ) ) ,
170+ id : 'rspress-route-home' ,
171+ path : undefined ,
172+ index : true ,
173+ } ,
174+ ]
175+ : [ ] ) ,
176+ ] ;
177+
79178 return {
80179 id : 'rspress-app-shell' ,
81180 path : '/' ,
82181 element : < AppShell /> ,
83182 children : [
84- ...routes . map ( ( route , index ) => toRouteObject ( route , index ) ) ,
183+ {
184+ id : 'rspress-route-canonical' ,
185+ element : < CanonicalRouteOutlet /> ,
186+ children : canonicalRoutes ,
187+ } ,
85188 {
86189 id : 'rspress-route-alias' ,
87190 path : '*' ,
88191 loader : ( { request } : { request : Request } ) =>
89- initPageData ( removeBase ( new URL ( request . url ) . pathname ) ) ,
192+ initPageData ( getCanonicalRoutePath ( new URL ( request . url ) . pathname ) ) ,
90193 element : < AliasRouteElement /> ,
91194 } ,
92195 ] ,
@@ -104,4 +207,9 @@ export function createRspressStaticRouter(
104207 return createStaticRouter ( [ createAppShellRoute ( routes ) ] , context ) ;
105208}
106209
107- export { createStaticHandler , RouterProvider , StaticRouterProvider } ;
210+ export {
211+ createDataRoutes ,
212+ createStaticHandler ,
213+ RouterProvider ,
214+ StaticRouterProvider ,
215+ } ;
0 commit comments