feat(core/router): migrate to react-router data mode and support react-router-dom@6#3306
feat(core/router): migrate to react-router data mode and support react-router-dom@6#3306SoonIter wants to merge 9 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Migrates the Rspress core runtime routing to React Router “data router” mode, while aiming to keep compatibility with react-router-dom@6, and adds automatic generation of localized/versioned 404 routes.
Changes:
- Introduces a new data-router based runtime router layer (
createRspressBrowserRouter/createRspressStaticRouter) and updates SSR/CSR entries to use loaders +StaticRouterProvider/RouterProvider. - Updates route generation to include a
loader(backed byinitPageData) and ensures framework 404 routes exist per lang/version. - Adjusts dependency/aliasing setup to support
react-router-dom@6and removes some plugin-levelreact-router-domdependencies.
Reviewed changes
Copilot reviewed 28 out of 30 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-workspace.yaml | Bumps workspace pnpm-plugin-skills version. |
| pnpm-lock.yaml | Removes react-router-dom from several importer dependency sets. |
| packages/shared/src/types/index.ts | Extends Route typing to support data-router fields (loader/version/etc). |
| packages/plugin-preview/package.json | Drops react-router-dom dependency/peerDependency from plugin package. |
| packages/plugin-playground/package.json | Drops react-router-dom dependency/peerDependency from plugin package. |
| packages/plugin-api-docgen/package.json | Drops react-router-dom dependency from plugin package. |
| packages/core/src/theme/components/Link/useLinkNavigate.ts | Switches link prefetching from page-data warming to route preload. |
| packages/core/src/runtime/ssrServerEntry.tsx | Migrates SSR HTML rendering to static data router + StaticRouterProvider. |
| packages/core/src/runtime/ssrMdServerEntry.tsx | Migrates SSR Markdown rendering to static data router + StaticRouterProvider. |
| packages/core/src/runtime/ssrClientEntry.tsx | Adjusts SSR hydration bootstrap (removes page-data cache sync). |
| packages/core/src/runtime/router.tsx | Adds shared browser/static router creators and AppShell wiring for data-router mode. |
| packages/core/src/runtime/pathnameToRouteService.ts | Lazily sorts routes to avoid touching virtual routes at module init. |
| packages/core/src/runtime/pathnameToRouteService.test.ts | Updates test import path for renamed route service module. |
| packages/core/src/runtime/initPageData.ts | Updates route lookup import path after route service refactor. |
| packages/core/src/runtime/index.ts | Re-exports new router helpers and adjusts runtime exports. |
| packages/core/src/runtime/hooks/usePage.ts | Makes page context data optional and throws if used before data is available. |
| packages/core/src/runtime/hooks/useActiveMatcher.ts | Updates isActive import to the new route service module. |
| packages/core/src/runtime/getSidebarDataGroup.test.ts | Updates isActive import to the new route service module. |
| packages/core/src/runtime/env.d.ts | Adds a react-router-dom/server ambient module declaration for compatibility. |
| packages/core/src/runtime/Content.tsx | Switches content rendering from manual route element + Suspense to useOutlet(). |
| packages/core/src/runtime/ClientApp.tsx | Replaces BrowserRouter with RouterProvider using the new browser router. |
| packages/core/src/runtime/App.tsx | Removes legacy page-data refetch/caching logic and relies on loader-provided data. |
| packages/core/src/node/utils/reactAlias.ts | Updates react-router-dom alias logic to handle v6 vs v7 (including /server). |
| packages/core/src/node/utils/reactAlias.test.ts | Updates alias snapshot expectations for new alias keys. |
| packages/core/src/node/ssg/renderPages.ts | Removes manual /404 injection (now handled by route service). |
| packages/core/src/node/route/RouteService.ts | Ensures framework 404 routes; adds loader into generated virtual routes; adjusts existence checks. |
| packages/core/src/node/route/RouteService.test.ts | Updates snapshots to include generated 404 routes and loader fields. |
| packages/core/src/node/route/RoutePage.ts | Adds createFrameworkFallback404 helper for internal 404 route pages. |
| packages/core/src/node/route/extractPageData.test.ts | Adjusts test cast to satisfy typing changes. |
| e2e/fixtures/react-router-dom-6/rspress.config.ts | Tweaks fixture config for the react-router-dom@6 compatibility scenario. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export const Content = ({ fallback = <></> }: { fallback?: ReactNode }) => { | ||
| const { pathname } = useLocation(); | ||
| const matchedElement = useMemo(() => { | ||
| const route = pathnameToRouteService(pathname); | ||
| return route?.element; | ||
| }, [pathname]); | ||
|
|
||
| return <Suspense fallback={fallback}>{matchedElement}</Suspense>; | ||
| const outlet = useOutlet(); | ||
| return outlet ?? fallback; |
| function AppShell() { | ||
| const matches = useMatches(); | ||
| const currentMatch = matches[matches.length - 1]; | ||
| const pageData = currentMatch?.data as Page | undefined; | ||
|
|
||
| return ( | ||
| <PageContext.Provider value={{ data: pageData }}> | ||
| <App /> | ||
| </PageContext.Provider> |
| export function createRspressBrowserRouter(routes: Route[], basename: string) { | ||
| return createBrowserRouter([ | ||
| { | ||
| id: 'rspress-app-shell', | ||
| path: '/', | ||
| element: <AppShell />, | ||
| children: routes.map((route, index) => toRouteObject(route, index)), | ||
| }, | ||
| ], { basename }); |
| if (route.pageName === '__rspress_fallback_404__') { | ||
| return `{ path: '${route.routePath}', element: React.createElement(React.Fragment), filePath: '', preload: async () => ({ default: React.Fragment }), loader: () => initPageData('${route.routePath}'), lang: '${route.lang}', version: '${route.version}' }`; | ||
| } |
| const cleanLinkPath = linkToRoutePath(link); | ||
| const routePaths = new Set(this.getRoutes().map(route => route.routePath)); | ||
| // allow fuzzy matching, e.g: /guide/ and /guide is equal | ||
| // This is a simple judgment, the performance will be better than "matchPath" in react-router-dom | ||
| if ( | ||
| !this.routeData.has(removeTrailingSlash(cleanLinkPath)) && | ||
| !this.routeData.has(addTrailingSlash(cleanLinkPath)) | ||
| !routePaths.has(removeTrailingSlash(cleanLinkPath)) && | ||
| !routePaths.has(addTrailingSlash(cleanLinkPath)) | ||
| ) { |
| export interface Route { | ||
| path: string; | ||
| element: React.ReactElement; | ||
| Component: React.ComponentType<unknown>; | ||
| filePath: string; | ||
| preload: () => Promise<PageModule<React.ComponentType<unknown>>>; | ||
| loader: () => Promise<PageDataLegacy['page']>; | ||
| lang: string; | ||
| version: string; |
Rsdoctor Bundle Diff AnalysisFound 3 projects in monorepo, 3 projects with changes. 📊 Quick Summary
📋 Detailed Reports (Click to expand)📁 nodePath:
📦 Download Diff Report: node Bundle Diff 📁 node_mdPath:
📦 Download Diff Report: node_md Bundle Diff 📁 webPath:
📦 Download Diff Report: web Bundle Diff Generated by Rsdoctor GitHub Action |
9ee1683 to
7202153
Compare
Summary
This PR migrates the Rspress core runtime to React Router data mode and adds compatibility for "react-router-dom@6". It also introduces support for versioned and localized 404 routes.
Related Issue
None
Checklist