Skip to content

Commit a7ea8cd

Browse files
authored
RSC: Include routing in initial RSC example app (#9611)
1 parent 02e3edc commit a7ea8cd

13 files changed

Lines changed: 271 additions & 25 deletions

packages/cli/src/commands/experimental/setupRscHandler.js

Lines changed: 125 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,45 @@ export const handler = async ({ force, verbose }) => {
9292
},
9393
},
9494
{
95-
title: 'Overwriting App.tsx...',
95+
title: 'Removing App.tsx...',
9696
task: async () => {
97-
const appTemplate = fs.readFileSync(
98-
path.resolve(__dirname, 'templates', 'rsc', 'App.tsx.template'),
97+
const appPath =
98+
rwPaths.web.app ?? path.join(rwPaths.web.src, 'App.tsx')
99+
100+
fs.rmSync(appPath, { force: true })
101+
},
102+
},
103+
{
104+
title: 'Adding Pages...',
105+
task: async () => {
106+
const homePageTemplate = fs.readFileSync(
107+
path.resolve(
108+
__dirname,
109+
'templates',
110+
'rsc',
111+
'HomePage.tsx.template'
112+
),
99113
'utf-8'
100114
)
101-
const appPath = rwPaths.web.app
115+
const homePagePath = path.join(rwPaths.web.src, 'HomePage.tsx')
102116

103-
writeFile(appPath, appTemplate, {
104-
overwriteExisting: true,
117+
writeFile(homePagePath, homePageTemplate, {
118+
overwriteExisting: force,
119+
})
120+
121+
const aboutPageTemplate = fs.readFileSync(
122+
path.resolve(
123+
__dirname,
124+
'templates',
125+
'rsc',
126+
'AboutPage.tsx.template'
127+
),
128+
'utf-8'
129+
)
130+
const aboutPagePath = path.join(rwPaths.web.src, 'AboutPage.tsx')
131+
132+
writeFile(aboutPagePath, aboutPageTemplate, {
133+
overwriteExisting: force,
105134
})
106135
},
107136
},
@@ -132,12 +161,16 @@ export const handler = async ({ force, verbose }) => {
132161
path: 'Counter.module.css',
133162
},
134163
{
135-
template: 'App.css.template',
136-
path: 'App.css',
164+
template: 'HomePage.css.template',
165+
path: 'HomePage.css',
137166
},
138167
{
139-
template: 'App.module.css.template',
140-
path: 'App.module.css',
168+
template: 'HomePage.module.css.template',
169+
path: 'HomePage.module.css',
170+
},
171+
{
172+
template: 'AboutPage.css.template',
173+
path: 'AboutPage.css',
141174
},
142175
]
143176

@@ -154,6 +187,44 @@ export const handler = async ({ force, verbose }) => {
154187
})
155188
},
156189
},
190+
{
191+
title: 'Adding Layout...',
192+
task: async () => {
193+
const layoutTemplate = fs.readFileSync(
194+
path.resolve(
195+
__dirname,
196+
'templates',
197+
'rsc',
198+
'NavigationLayout.tsx.template'
199+
),
200+
'utf-8'
201+
)
202+
const layoutPath = path.join(
203+
rwPaths.web.layouts,
204+
'NavigationLayout',
205+
'NavigationLayout.tsx'
206+
)
207+
208+
writeFile(layoutPath, layoutTemplate, { overwriteExisting: force })
209+
210+
const cssTemplate = fs.readFileSync(
211+
path.resolve(
212+
__dirname,
213+
'templates',
214+
'rsc',
215+
'NavigationLayout.css.template'
216+
),
217+
'utf-8'
218+
)
219+
const cssPath = path.join(
220+
rwPaths.web.layouts,
221+
'NavigationLayout',
222+
'NavigationLayout.css'
223+
)
224+
225+
writeFile(cssPath, cssTemplate, { overwriteExisting: force })
226+
},
227+
},
157228
{
158229
title: 'Updating index.html...',
159230
task: async () => {
@@ -170,14 +241,30 @@ export const handler = async ({ force, verbose }) => {
170241

171242
indexHtml = indexHtml.replace(
172243
'href="/favicon.png" />',
173-
'href="/favicon.png" />\n <script type="module" src="entry.client.tsx"></script>'
244+
'href="/favicon.png" />\n' +
245+
' <link rel="stylesheet" href="index.css" />\n' +
246+
' <script type="module" src="entry.client.tsx"></script>'
174247
)
175248

176249
writeFile(rwPaths.web.html, indexHtml, {
177250
overwriteExisting: true,
178251
})
179252
},
180253
},
254+
{
255+
title: 'Overwriting index.css...',
256+
task: async () => {
257+
const template = fs.readFileSync(
258+
path.resolve(__dirname, 'templates', 'rsc', 'index.css.template'),
259+
'utf-8'
260+
)
261+
const filePath = path.join(rwPaths.web.src, 'index.css')
262+
263+
writeFile(filePath, template, {
264+
overwriteExisting: true,
265+
})
266+
},
267+
},
181268
{
182269
title: 'Overwrite entry.client.tsx...',
183270
task: async () => {
@@ -196,6 +283,18 @@ export const handler = async ({ force, verbose }) => {
196283
})
197284
},
198285
},
286+
{
287+
title: 'Updating entry.server.tsx...',
288+
task: async () => {
289+
let entryServer = fs.readFileSync(rwPaths.web.entryServer, 'utf-8')
290+
291+
entryServer = entryServer.replaceAll('App', 'HomePage')
292+
293+
writeFile(rwPaths.web.entryServer, entryServer, {
294+
overwriteExisting: true,
295+
})
296+
},
297+
},
199298
{
200299
title: 'Add React experimental types',
201300
task: async () => {
@@ -217,6 +316,21 @@ export const handler = async ({ force, verbose }) => {
217316
)
218317
},
219318
},
319+
// TODO (RSC): Remove this once we have a better way to handle routes.
320+
// This is a total hack right now
321+
{
322+
title: 'Overwriting routes...',
323+
task: async () => {
324+
const routesTemplate = fs.readFileSync(
325+
path.resolve(__dirname, 'templates', 'rsc', 'Routes.tsx.template'),
326+
'utf-8'
327+
)
328+
329+
writeFile(rwPaths.web.routes, routesTemplate, {
330+
overwriteExisting: true,
331+
})
332+
},
333+
},
220334
{
221335
title: 'Patch vite',
222336
task: async () => {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.about-page {
2+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Assets } from '@redwoodjs/vite/assets'
2+
import { ProdRwRscServerGlobal } from '@redwoodjs/vite/rwRscGlobal'
3+
4+
import { Counter } from './Counter'
5+
6+
import './AboutPage.css'
7+
8+
// TODO (RSC) Something like this will probably be needed
9+
// const RwRscGlobal = import.meta.env.PROD ? ProdRwRscServerGlobal : DevRwRscServerGlobal;
10+
11+
globalThis.rwRscGlobal = new ProdRwRscServerGlobal()
12+
13+
const AboutPage = () => {
14+
return (
15+
<div className="about-page">
16+
{/* TODO (RSC) <Assets /> should be part of the router later */}
17+
<Assets />
18+
<div style={{ border: '3px red dashed', margin: '1em', padding: '1em' }}>
19+
<h1>About Redwood</h1>
20+
<Counter />
21+
</div>
22+
</div>
23+
)
24+
}
25+
26+
export default AboutPage

packages/cli/src/commands/experimental/templates/rsc/App.css.template

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.home-page {
2+
}

packages/cli/src/commands/experimental/templates/rsc/App.module.css.template renamed to packages/cli/src/commands/experimental/templates/rsc/HomePage.module.css.template

File renamed without changes.

packages/cli/src/commands/experimental/templates/rsc/App.tsx.template renamed to packages/cli/src/commands/experimental/templates/rsc/HomePage.tsx.template

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
import { Assets } from '@redwoodjs/vite/assets'
22
import { ProdRwRscServerGlobal } from '@redwoodjs/vite/rwRscGlobal'
33

4-
// @ts-expect-error no types
5-
import styles from './App.module.css'
64
import { Counter } from './Counter'
5+
// @ts-expect-error no types
6+
import styles from './HomePage.module.css'
77

8-
import './App.css'
8+
import './HomePage.css'
99

1010
// TODO (RSC) Something like this will probably be needed
1111
// const RwRscGlobal = import.meta.env.PROD ? ProdRwRscServerGlobal : DevRwRscServerGlobal;
1212

1313
globalThis.rwRscGlobal = new ProdRwRscServerGlobal()
1414

15-
const App = ({ name = 'Anonymous' }) => {
15+
const HomePage = ({ name = 'Anonymous' }) => {
1616
return (
17-
<>
17+
<div className="home-page">
1818
{/* TODO (RSC) <Assets /> should be part of the router later */}
1919
<Assets />
2020
<div style={{ border: '3px red dashed', margin: '1em', padding: '1em' }}>
2121
<h1 className={styles.title}>Hello {name}!!</h1>
2222
<h3>This is a server component.</h3>
2323
<Counter />
2424
</div>
25-
</>
25+
</div>
2626
)
2727
}
2828

29-
export default App
29+
export default HomePage
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
.navigation-layout {
2+
& nav {
3+
display: flex;
4+
justify-content: space-between;
5+
align-items: center;
6+
padding: 10px;
7+
background-color: color-mix(in srgb, yellow 50%, transparent);
8+
border-bottom: 2px dashed color-mix(in srgb, yellow 90%, black);
9+
}
10+
11+
& ul {
12+
list-style: none;
13+
display: flex;
14+
margin: 0;
15+
padding: 0;
16+
}
17+
18+
& li {
19+
margin-right: 10px;
20+
}
21+
22+
& a {
23+
text-decoration: none;
24+
color: #333;
25+
padding: 5px;
26+
border-bottom: 2px solid transparent;
27+
}
28+
29+
& a:hover {
30+
border-bottom: 2px solid #333;
31+
}
32+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Link, routes } from '@redwoodjs/router'
2+
3+
import './NavigationLayout.css'
4+
5+
type NavigationLayoutProps = {
6+
children?: React.ReactNode
7+
}
8+
9+
const NavigationLayout = ({ children }: NavigationLayoutProps) => {
10+
return (
11+
<div className="navigation-layout">
12+
<nav>
13+
<ul>
14+
<li>
15+
<Link to={routes.home()}>Home</Link>
16+
</li>
17+
<li>
18+
<Link to={routes.about()}>About</Link>
19+
</li>
20+
</ul>
21+
</nav>
22+
<main>{children}</main>
23+
</div>
24+
)
25+
}
26+
27+
export default NavigationLayout
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// In this file, all Page components from 'src/pages` are auto-imported. Nested
2+
// directories are supported, and should be uppercase. Each subdirectory will be
3+
// prepended onto the component name.
4+
//
5+
// Examples:
6+
//
7+
// 'src/pages/HomePage/HomePage.js' -> HomePage
8+
// 'src/pages/Admin/BooksPage/BooksPage.js' -> AdminBooksPage
9+
10+
import { Router, Route } from '@redwoodjs/router'
11+
12+
const Routes = () => {
13+
return (
14+
<Router>
15+
<Route path="/about" page={AboutPage} name="about" />
16+
<Route path="/" page={HomePage} name="home" />
17+
<Route notfound page={NotFoundPage} />
18+
</Router>
19+
)
20+
}
21+
22+
export default Routes

0 commit comments

Comments
 (0)