Skip to content

Commit 7202153

Browse files
committed
chore: update
1 parent e8e7161 commit 7202153

6 files changed

Lines changed: 131 additions & 56 deletions

File tree

packages/core/src/runtime/ClientApp.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@ export function ClientApp({
3232
<ThemeContext.Provider
3333
value={useMemo(() => ({ theme, setTheme }), [theme, setTheme])}
3434
>
35-
<UnheadProvider head={head}>
36-
<RouterProvider router={router} />
37-
</UnheadProvider>
35+
<PageContext.Provider
36+
value={useMemo(() => ({ data: initialPageData }), [initialPageData])}
37+
>
38+
<UnheadProvider head={head}>
39+
<RouterProvider router={router} />
40+
</UnheadProvider>
41+
</PageContext.Provider>
3842
</ThemeContext.Provider>
3943
);
4044
}

packages/core/src/runtime/initPageData.ts

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,17 @@ type PageMeta = {
2121
export type Page = PageDataLegacy['page'];
2222

2323
export async function initPageData(routePath: string): Promise<Page> {
24-
const normalizedRoutePath = routePath
25-
.replace(/\.html(?=#|\?|$)/, '')
26-
.replace(/\/index(?=\/|$|#|\?)/, '/');
27-
28-
const matchedRoute = pathnameToRouteService(normalizedRoutePath);
24+
const matchedRoute = pathnameToRouteService(routePath);
2925
if (matchedRoute) {
3026
// Preload route component
3127
const mod = await matchedRoute.preload();
3228
const pagePath = cleanUrl(matchedRoute.filePath);
3329
const normalize = (p: string) =>
3430
// compat the path that has no / suffix and ignore case
3531
p.replace(/\/$/, '').toLowerCase();
36-
const extractPageInfo: BaseRuntimePageInfo | undefined = pageData.pages.find(
37-
page => isEqualPath(normalize(page.routePath), normalize(matchedRoute.path)),
38-
);
39-
40-
if (!extractPageInfo) {
41-
return {
42-
pagePath: '',
43-
pageType: '404',
44-
routePath: '/404',
45-
lang: siteData.lang || '',
46-
frontmatter: {},
47-
title: '404',
48-
toc: [],
49-
version: siteData.multiVersion?.default || '',
50-
_filepath: '',
51-
_relativePath: '',
52-
};
53-
}
32+
const extractPageInfo: BaseRuntimePageInfo = pageData.pages.find(page =>
33+
isEqualPath(normalize(page.routePath), normalize(matchedRoute.path)),
34+
)!;
5435

5536
// FIXME: when sidebar item is configured as link string, the sidebar text won't updated when page title changed
5637
// Reason: The sidebar item text depends on pageData, which is not updated when page title changed, because the pageData is computed once when build

packages/core/src/runtime/pathnameToRouteService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function matchPath(
4141
pathname: string,
4242
): { path: string } | null {
4343
if (pattern === '*') {
44-
return { path: pattern };
44+
return normalizeRoutePath(pathname) === '/404' ? { path: pattern } : null;
4545
}
4646

4747
if (pattern === '/' && normalizeRoutePath(pathname) !== '/') {

packages/core/src/runtime/router.tsx

Lines changed: 115 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Route } from '@rspress/shared';
22
import {
33
createBrowserRouter,
4+
Outlet,
45
RouterProvider,
56
type StaticHandlerContext,
67
useLocation,
@@ -23,17 +24,25 @@ import { removeBase } from './utils';
2324

2425
declare 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+
3039
function 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

6271
function 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+
6982
function 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+
78153
function 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+
};

packages/core/src/runtime/ssrMdServerEntry.tsx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
createDataRoutes,
23
createRspressStaticRouter,
34
createStaticHandler,
45
removeTrailingSlash,
@@ -17,17 +18,7 @@ export async function render(
1718
head: Unhead,
1819
): Promise<{ appMd: string }> {
1920
const basename = removeTrailingSlash(withBase('/'));
20-
const dataRoutes = [
21-
{
22-
id: 'rspress-app-shell',
23-
path: '/',
24-
children: routes.map((route, index) => ({
25-
id: `rspress-route-${index}`,
26-
path: route.path,
27-
loader: route.loader,
28-
})),
29-
},
30-
];
21+
const dataRoutes = createDataRoutes(routes);
3122
const handler = createStaticHandler(dataRoutes, { basename });
3223
const context = await handler.query(
3324
new Request(`http://rspress.local${withBase(routePath)}`),

packages/core/src/runtime/ssrServerEntry.tsx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { PassThrough } from 'node:stream';
22
import { text } from 'node:stream/consumers';
33
import {
4+
createDataRoutes,
45
createRspressStaticRouter,
56
createStaticHandler,
67
removeTrailingSlash,
@@ -37,17 +38,7 @@ export async function render(
3738
head: Unhead,
3839
): Promise<{ appHtml: string }> {
3940
const basename = removeTrailingSlash(withBase('/'));
40-
const dataRoutes = [
41-
{
42-
id: 'rspress-app-shell',
43-
path: '/',
44-
children: routes.map((route, index) => ({
45-
id: `rspress-route-${index}`,
46-
path: route.path,
47-
loader: route.loader,
48-
})),
49-
},
50-
];
41+
const dataRoutes = createDataRoutes(routes);
5142
const handler = createStaticHandler(dataRoutes, { basename });
5243
const context = await handler.query(
5344
new Request(`http://rspress.local${withBase(routePath)}`),

0 commit comments

Comments
 (0)