Skip to content

Commit

Permalink
RSC: Include routing in initial RSC example app (#9611)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobbe authored Dec 1, 2023
1 parent 02e3edc commit a7ea8cd
Show file tree
Hide file tree
Showing 13 changed files with 271 additions and 25 deletions.
136 changes: 125 additions & 11 deletions packages/cli/src/commands/experimental/setupRscHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,45 @@ export const handler = async ({ force, verbose }) => {
},
},
{
title: 'Overwriting App.tsx...',
title: 'Removing App.tsx...',
task: async () => {
const appTemplate = fs.readFileSync(
path.resolve(__dirname, 'templates', 'rsc', 'App.tsx.template'),
const appPath =
rwPaths.web.app ?? path.join(rwPaths.web.src, 'App.tsx')

fs.rmSync(appPath, { force: true })
},
},
{
title: 'Adding Pages...',
task: async () => {
const homePageTemplate = fs.readFileSync(
path.resolve(
__dirname,
'templates',
'rsc',
'HomePage.tsx.template'
),
'utf-8'
)
const appPath = rwPaths.web.app
const homePagePath = path.join(rwPaths.web.src, 'HomePage.tsx')

writeFile(appPath, appTemplate, {
overwriteExisting: true,
writeFile(homePagePath, homePageTemplate, {
overwriteExisting: force,
})

const aboutPageTemplate = fs.readFileSync(
path.resolve(
__dirname,
'templates',
'rsc',
'AboutPage.tsx.template'
),
'utf-8'
)
const aboutPagePath = path.join(rwPaths.web.src, 'AboutPage.tsx')

writeFile(aboutPagePath, aboutPageTemplate, {
overwriteExisting: force,
})
},
},
Expand Down Expand Up @@ -132,12 +161,16 @@ export const handler = async ({ force, verbose }) => {
path: 'Counter.module.css',
},
{
template: 'App.css.template',
path: 'App.css',
template: 'HomePage.css.template',
path: 'HomePage.css',
},
{
template: 'App.module.css.template',
path: 'App.module.css',
template: 'HomePage.module.css.template',
path: 'HomePage.module.css',
},
{
template: 'AboutPage.css.template',
path: 'AboutPage.css',
},
]

Expand All @@ -154,6 +187,44 @@ export const handler = async ({ force, verbose }) => {
})
},
},
{
title: 'Adding Layout...',
task: async () => {
const layoutTemplate = fs.readFileSync(
path.resolve(
__dirname,
'templates',
'rsc',
'NavigationLayout.tsx.template'
),
'utf-8'
)
const layoutPath = path.join(
rwPaths.web.layouts,
'NavigationLayout',
'NavigationLayout.tsx'
)

writeFile(layoutPath, layoutTemplate, { overwriteExisting: force })

const cssTemplate = fs.readFileSync(
path.resolve(
__dirname,
'templates',
'rsc',
'NavigationLayout.css.template'
),
'utf-8'
)
const cssPath = path.join(
rwPaths.web.layouts,
'NavigationLayout',
'NavigationLayout.css'
)

writeFile(cssPath, cssTemplate, { overwriteExisting: force })
},
},
{
title: 'Updating index.html...',
task: async () => {
Expand All @@ -170,14 +241,30 @@ export const handler = async ({ force, verbose }) => {

indexHtml = indexHtml.replace(
'href="/favicon.png" />',
'href="/favicon.png" />\n <script type="module" src="entry.client.tsx"></script>'
'href="/favicon.png" />\n' +
' <link rel="stylesheet" href="index.css" />\n' +
' <script type="module" src="entry.client.tsx"></script>'
)

writeFile(rwPaths.web.html, indexHtml, {
overwriteExisting: true,
})
},
},
{
title: 'Overwriting index.css...',
task: async () => {
const template = fs.readFileSync(
path.resolve(__dirname, 'templates', 'rsc', 'index.css.template'),
'utf-8'
)
const filePath = path.join(rwPaths.web.src, 'index.css')

writeFile(filePath, template, {
overwriteExisting: true,
})
},
},
{
title: 'Overwrite entry.client.tsx...',
task: async () => {
Expand All @@ -196,6 +283,18 @@ export const handler = async ({ force, verbose }) => {
})
},
},
{
title: 'Updating entry.server.tsx...',
task: async () => {
let entryServer = fs.readFileSync(rwPaths.web.entryServer, 'utf-8')

entryServer = entryServer.replaceAll('App', 'HomePage')

writeFile(rwPaths.web.entryServer, entryServer, {
overwriteExisting: true,
})
},
},
{
title: 'Add React experimental types',
task: async () => {
Expand All @@ -217,6 +316,21 @@ export const handler = async ({ force, verbose }) => {
)
},
},
// TODO (RSC): Remove this once we have a better way to handle routes.
// This is a total hack right now
{
title: 'Overwriting routes...',
task: async () => {
const routesTemplate = fs.readFileSync(
path.resolve(__dirname, 'templates', 'rsc', 'Routes.tsx.template'),
'utf-8'
)

writeFile(rwPaths.web.routes, routesTemplate, {
overwriteExisting: true,
})
},
},
{
title: 'Patch vite',
task: async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.about-page {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Assets } from '@redwoodjs/vite/assets'
import { ProdRwRscServerGlobal } from '@redwoodjs/vite/rwRscGlobal'

import { Counter } from './Counter'

import './AboutPage.css'

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

globalThis.rwRscGlobal = new ProdRwRscServerGlobal()

const AboutPage = () => {
return (
<div className="about-page">
{/* TODO (RSC) <Assets /> should be part of the router later */}
<Assets />
<div style={{ border: '3px red dashed', margin: '1em', padding: '1em' }}>
<h1>About Redwood</h1>
<Counter />
</div>
</div>
)
}

export default AboutPage

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.home-page {
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import { Assets } from '@redwoodjs/vite/assets'
import { ProdRwRscServerGlobal } from '@redwoodjs/vite/rwRscGlobal'

// @ts-expect-error no types
import styles from './App.module.css'
import { Counter } from './Counter'
// @ts-expect-error no types
import styles from './HomePage.module.css'

import './App.css'
import './HomePage.css'

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

globalThis.rwRscGlobal = new ProdRwRscServerGlobal()

const App = ({ name = 'Anonymous' }) => {
const HomePage = ({ name = 'Anonymous' }) => {
return (
<>
<div className="home-page">
{/* TODO (RSC) <Assets /> should be part of the router later */}
<Assets />
<div style={{ border: '3px red dashed', margin: '1em', padding: '1em' }}>
<h1 className={styles.title}>Hello {name}!!</h1>
<h3>This is a server component.</h3>
<Counter />
</div>
</>
</div>
)
}

export default App
export default HomePage
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.navigation-layout {
& nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background-color: color-mix(in srgb, yellow 50%, transparent);
border-bottom: 2px dashed color-mix(in srgb, yellow 90%, black);
}

& ul {
list-style: none;
display: flex;
margin: 0;
padding: 0;
}

& li {
margin-right: 10px;
}

& a {
text-decoration: none;
color: #333;
padding: 5px;
border-bottom: 2px solid transparent;
}

& a:hover {
border-bottom: 2px solid #333;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Link, routes } from '@redwoodjs/router'

import './NavigationLayout.css'

type NavigationLayoutProps = {
children?: React.ReactNode
}

const NavigationLayout = ({ children }: NavigationLayoutProps) => {
return (
<div className="navigation-layout">
<nav>
<ul>
<li>
<Link to={routes.home()}>Home</Link>
</li>
<li>
<Link to={routes.about()}>About</Link>
</li>
</ul>
</nav>
<main>{children}</main>
</div>
)
}

export default NavigationLayout
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// In this file, all Page components from 'src/pages` are auto-imported. Nested
// directories are supported, and should be uppercase. Each subdirectory will be
// prepended onto the component name.
//
// Examples:
//
// 'src/pages/HomePage/HomePage.js' -> HomePage
// 'src/pages/Admin/BooksPage/BooksPage.js' -> AdminBooksPage

import { Router, Route } from '@redwoodjs/router'

const Routes = () => {
return (
<Router>
<Route path="/about" page={AboutPage} name="about" />
<Route path="/" page={HomePage} name="home" />
<Route notfound page={NotFoundPage} />
</Router>
)
}

export default Routes
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ export default defineEntries(
// getEntry
async (id) => {
switch (id) {
case 'App':
return import('./App')
case 'AboutPage':
return import('./AboutPage')
case 'HomePage':
return import('./HomePage')
default:
return null
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
import { createRoot } from 'react-dom/client'

import { Route, Router, Set } from '@redwoodjs/router'
import { serve } from '@redwoodjs/vite/client'

import NavigationLayout from './layouts/NavigationLayout/NavigationLayout'
import NotFoundPage from './pages/NotFoundPage/NotFoundPage'

const redwoodAppElement = document.getElementById('redwood-app')

const App = serve('App')
const AboutPage = serve('AboutPage')
const HomePage = serve('HomePage')

const root = createRoot(redwoodAppElement)
root.render(<App name="Redwood RSCs" />)

const App = () => {
return (
<Router>
<Set wrap={NavigationLayout}>
<Route path="/" page={HomePage} name="home" />
<Route path="/about" page={AboutPage} name="about" />
</Set>
<Route notfound page={NotFoundPage} />
</Router>
)
}

root.render(<App />)
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
html, body {
margin: 0;
padding: 0;
}

0 comments on commit a7ea8cd

Please sign in to comment.