File tree Expand file tree Collapse file tree 10 files changed +1328
-230
lines changed Expand file tree Collapse file tree 10 files changed +1328
-230
lines changed Original file line number Diff line number Diff line change 41
41
"react" : " ^19.1.0" ,
42
42
"react-dom" : " ^19.1.0" ,
43
43
"react-markdown" : " ^10.1.0" ,
44
+ "react-router" : " ^7.7.1" ,
44
45
"rehype-slug" : " ^6.0.0" ,
45
46
"rehype-stringify" : " ^10.0.1" ,
46
47
"remark-comment" : " ^1.0.0" ,
57
58
"vfile-matter" : " ^5.0.0"
58
59
},
59
60
"scripts" : {
60
- "dev" : " next " ,
61
+ "dev" : " vite " ,
61
62
"res:watch" : " rescript build -w" ,
62
63
"build" : " rescript && npm run update-index && next build" ,
63
64
"test" : " node scripts/test-examples.mjs && node scripts/test-hrefs.mjs" ,
69
70
},
70
71
"devDependencies" : {
71
72
"@mdx-js/react" : " ^2.3.0" ,
73
+ "@vitejs/plugin-react" : " ^4.7.0" ,
74
+ "@vitejs/plugin-rsc" : " ^0.4.16" ,
72
75
"autoprefixer" : " ^10.4.14" ,
73
76
"cssnano" : " ^6.0.1" ,
74
77
"dotenv" : " ^16.4.7" ,
79
82
"postcss-nesting" : " ^12.1.1" ,
80
83
"reanalyze" : " ^2.16.0" ,
81
84
"simple-functional-loader" : " ^1.2.1" ,
82
- "tailwindcss" : " ^3.3.3"
85
+ "tailwindcss" : " ^3.3.3" ,
86
+ "vite" : " ^7.0.6"
83
87
}
84
- }
88
+ }
Original file line number Diff line number Diff line change
1
+
2
+ export function routes ( ) {
3
+ return [
4
+ {
5
+ id : "root" ,
6
+ path : "" ,
7
+ lazy : ( ) => import ( "./root/route.jsx" ) ,
8
+ children : [
9
+ {
10
+ id : "home" ,
11
+ index : true ,
12
+ lazy : ( ) => import ( "./home/route.jsx" )
13
+ }
14
+ ] ,
15
+ } ,
16
+ ]
17
+ }
Original file line number Diff line number Diff line change
1
+ import { make as LandingPageLayout } from "../../src/layouts/LandingPageLayout.mjs" ;
2
+
3
+ export default function Home ( ) {
4
+ return < LandingPageLayout />
5
+ }
Original file line number Diff line number Diff line change
1
+ "use client" ;
2
+
3
+ import {
4
+ isRouteErrorResponse ,
5
+ Link ,
6
+ NavLink ,
7
+ useNavigation ,
8
+ useRouteError ,
9
+ } from "react-router" ;
10
+
11
+ export function Layout ( { children } ) {
12
+ const navigation = useNavigation ( ) ;
13
+ return (
14
+ < html lang = "en" >
15
+ < head >
16
+ < meta charSet = "utf-8" />
17
+ < meta name = "viewport" content = "width=device-width, initial-scale=1" />
18
+ < link rel = "icon" type = "image/x-icon" href = "/favicon.ico" />
19
+ </ head >
20
+ < body className = "font-sans antialiased" >
21
+ < header className = "sticky inset-x-0 top-0 z-50 bg-background border-b" >
22
+ < div className = "mx-auto max-w-screen-xl px-4 relative flex h-16 items-center justify-between gap-4 sm:gap-8" >
23
+ < div className = "flex items-center gap-4" >
24
+ < Link to = "/" > React Router 🚀</ Link >
25
+ < nav >
26
+ < ul className = "gap-4 flex" >
27
+ < li >
28
+ < NavLink
29
+ to = "/"
30
+ className = "text-sm font-medium hover:opacity-75 aria-[current]:opacity-75"
31
+ >
32
+ Home
33
+ </ NavLink >
34
+ </ li >
35
+ < li >
36
+ < NavLink
37
+ to = "/about"
38
+ className = "text-sm font-medium hover:opacity-75 aria-[current]:opacity-75"
39
+ >
40
+ About
41
+ </ NavLink >
42
+ </ li >
43
+ </ ul >
44
+ </ nav >
45
+ < div > { navigation . state !== "idle" && < p > Loading...</ p > } </ div >
46
+ </ div >
47
+ </ div >
48
+ </ header >
49
+ { children }
50
+ </ body >
51
+ </ html >
52
+ ) ;
53
+ }
54
+
55
+ export function ErrorBoundary ( ) {
56
+ const error = useRouteError ( ) ;
57
+ let status = 500 ;
58
+ let message = "An unexpected error occurred." ;
59
+
60
+ if ( isRouteErrorResponse ( error ) ) {
61
+ status = error . status ;
62
+ message = status === 404 ? "Page not found." : error . statusText || message ;
63
+ }
64
+
65
+ return (
66
+ < main className = "mx-auto max-w-screen-xl px-4 py-8 lg:py-12" >
67
+ < article className = "prose mx-auto" >
68
+ < h1 > { status } </ h1 >
69
+ < p > { message } </ p >
70
+ </ article >
71
+ </ main >
72
+ ) ;
73
+ }
Original file line number Diff line number Diff line change
1
+ import { Outlet } from "react-router" ;
2
+
3
+ import "../../styles/main.css" ;
4
+ import "../../styles/utils.css" ;
5
+ // import "codemirror/lib/codemirror.css";
6
+ // import "styles/cm.css";
7
+ // import "styles/docson.css";
8
+
9
+ import { Layout as ClientLayout } from "./client" ;
10
+
11
+ export { ErrorBoundary } from "./client" ;
12
+
13
+ export function Layout ( { children } ) {
14
+ // This is necessary for the bundler to inject the needed CSS assets.
15
+ return < ClientLayout > { children } </ ClientLayout > ;
16
+ }
17
+
18
+ export default function Component ( ) {
19
+ return < Outlet /> ;
20
+ }
Original file line number Diff line number Diff line change
1
+ import {
2
+ createFromReadableStream ,
3
+ createTemporaryReferenceSet ,
4
+ encodeReply ,
5
+ setServerCallback ,
6
+ } from "@vitejs/plugin-rsc/browser" ;
7
+ import { startTransition , StrictMode } from "react" ;
8
+ import { hydrateRoot } from "react-dom/client" ;
9
+ import {
10
+ unstable_createCallServer as createCallServer ,
11
+ unstable_getRSCStream as getRSCStream ,
12
+ unstable_RSCHydratedRouter as RSCHydratedRouter ,
13
+ } from "react-router" ;
14
+
15
+ // Create and set the callServer function to support post-hydration server actions.
16
+ setServerCallback (
17
+ createCallServer ( {
18
+ createFromReadableStream,
19
+ createTemporaryReferenceSet,
20
+ encodeReply,
21
+ } ) ,
22
+ ) ;
23
+
24
+ // Get and decode the initial server payload.
25
+ createFromReadableStream (
26
+ getRSCStream ( ) ,
27
+ ) . then ( ( payload ) => {
28
+ startTransition ( async ( ) => {
29
+ const formState =
30
+ payload . type === "render"
31
+ ? await payload . formState
32
+ : undefined ;
33
+
34
+ hydrateRoot (
35
+ document ,
36
+ < StrictMode >
37
+ < RSCHydratedRouter
38
+ createFromReadableStream = {
39
+ createFromReadableStream
40
+ }
41
+ payload = { payload }
42
+ />
43
+ </ StrictMode > ,
44
+ {
45
+ formState,
46
+ } ,
47
+ ) ;
48
+ } ) ;
49
+ } ) ;
Original file line number Diff line number Diff line change
1
+ import {
2
+ createTemporaryReferenceSet ,
3
+ decodeAction ,
4
+ decodeFormState ,
5
+ decodeReply ,
6
+ loadServerAction ,
7
+ renderToReadableStream ,
8
+ } from "@vitejs/plugin-rsc/rsc" ;
9
+ import { unstable_matchRSCServerRequest as matchRSCServerRequest } from "react-router" ;
10
+
11
+ import { routes } from "../routes/config" ;
12
+
13
+ function fetchServer ( request ) {
14
+ return matchRSCServerRequest ( {
15
+ // Provide the React Server touchpoints.
16
+ createTemporaryReferenceSet,
17
+ decodeAction,
18
+ decodeFormState,
19
+ decodeReply,
20
+ loadServerAction,
21
+ // The incoming request.
22
+ request,
23
+ // The app routes.
24
+ routes : routes ( ) ,
25
+ // Encode the match with the React Server implementation.
26
+ generateResponse ( match ) {
27
+ return new Response (
28
+ renderToReadableStream ( match . payload ) ,
29
+ {
30
+ status : match . statusCode ,
31
+ headers : match . headers ,
32
+ } ,
33
+ ) ;
34
+ } ,
35
+ } ) ;
36
+ }
37
+
38
+ export default async function handler ( request ) {
39
+ // Import the generateHTML function from the client environment
40
+ const ssr = await import . meta. viteRsc . loadModule ( "ssr" , "index" ) ;
41
+
42
+ return ssr . generateHTML ( request , fetchServer ) ;
43
+ }
Original file line number Diff line number Diff line change
1
+ import { createFromReadableStream } from "@vitejs/plugin-rsc/ssr" ;
2
+ import { renderToReadableStream as renderHTMLToReadableStream } from "react-dom/server.edge" ;
3
+ import {
4
+ unstable_routeRSCServerRequest as routeRSCServerRequest ,
5
+ unstable_RSCStaticRouter as RSCStaticRouter ,
6
+ } from "react-router" ;
7
+
8
+ export async function generateHTML (
9
+ request ,
10
+ fetchServer ,
11
+ ) {
12
+ return await routeRSCServerRequest ( {
13
+ // The incoming request.
14
+ request,
15
+ // How to call the React Server.
16
+ fetchServer,
17
+ // Provide the React Server touchpoints.
18
+ createFromReadableStream,
19
+ // Render the router to HTML.
20
+ async renderHTML ( getPayload ) {
21
+ const payload = await getPayload ( ) ;
22
+ const formState =
23
+ payload . type === "render"
24
+ ? await payload . formState
25
+ : undefined ;
26
+
27
+ const bootstrapScriptContent =
28
+ await import . meta. viteRsc . loadBootstrapScriptContent (
29
+ "index" ,
30
+ ) ;
31
+
32
+ return await renderHTMLToReadableStream (
33
+ < RSCStaticRouter getPayload = { getPayload } /> ,
34
+ {
35
+ bootstrapScriptContent,
36
+ formState,
37
+ } ,
38
+ ) ;
39
+ } ,
40
+ } ) ;
41
+ }
Original file line number Diff line number Diff line change
1
+ import react from "@vitejs/plugin-react" ;
2
+ import rsc from "@vitejs/plugin-rsc/plugin" ;
3
+ import { defineConfig } from "vite" ;
4
+
5
+ export default defineConfig ( {
6
+ plugins : [
7
+ react ( ) ,
8
+ rsc ( {
9
+ entries : {
10
+ client : "src/entry.browser.jsx" ,
11
+ rsc : "src/entry.rsc.jsx" ,
12
+ ssr : "src/entry.ssr.jsx" ,
13
+ } ,
14
+ } ) ,
15
+ ] ,
16
+ } ) ;
You can’t perform that action at this time.
0 commit comments