Skip to content

Commit

Permalink
RSC Client Router (redwoodjs#10557)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobbe committed May 22, 2024
1 parent 2eedf5d commit 5adb761
Show file tree
Hide file tree
Showing 26 changed files with 584 additions and 178 deletions.
11 changes: 8 additions & 3 deletions __fixtures__/test-project-rsa/web/src/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,19 @@
// 'src/pages/HomePage/HomePage.js' -> HomePage
// 'src/pages/Admin/BooksPage/BooksPage.js' -> AdminBooksPage

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

// @ts-expect-error - ESM issue. RW projects need to be ESM to properly pick up
// on the types here
import { Router } from '@redwoodjs/vite/Router'

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

const Routes = () => {
const Routes = ({ location }: { location?: any }) => {
return (
<Router>
<Router location={location}>
<Set wrap={NavigationLayout}>
<Route path="/" page={HomePage} name="home" />
<Route path="/about" page={AboutPage} name="about" />
Expand Down
10 changes: 8 additions & 2 deletions __fixtures__/test-project-rsa/web/src/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import type { TagDescriptor } from '@redwoodjs/web/dist/components/htmlTags'

import { Document } from './Document'
import Routes from './Routes'

interface Props {
css: string[]
meta?: TagDescriptor[]
location: {
pathname: string
hash?: string
search?: string
}
}

export const ServerEntry: React.FC<Props> = ({ css, meta }) => {
export const ServerEntry: React.FC<Props> = ({ css, meta, location }) => {
return (
<Document css={css} meta={meta}>
<div>App</div>
<Routes location={location} />
</Document>
)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { Link, routes } from '@redwoodjs/router'
import { namedRoutes as routes } from '@redwoodjs/router/dist/namedRoutes'

import './NavigationLayout.css'

type NavigationLayoutProps = {
children?: React.ReactNode
}

const Link = (props: any) => {
return <a href={props.to}>{props.children}</a>
}

const NavigationLayout = ({ children }: NavigationLayoutProps) => {
return (
<div className="navigation-layout">
Expand Down
20 changes: 12 additions & 8 deletions __fixtures__/test-project-rsc-kitchen-sink/web/src/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,34 @@
// 'src/pages/HomePage/HomePage.js' -> HomePage
// 'src/pages/Admin/BooksPage/BooksPage.js' -> AdminBooksPage

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

// @ts-expect-error - ESM issue. RW projects need to be ESM to properly pick up
// on the types here
import { Router } from '@redwoodjs/vite/Router'

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

const Routes = () => {
const Routes = ({ location }: { location?: any }) => {
return (
<Router>
<Set wrap={NavigationLayout}>
<Router location={location}>
<Set wrap={NavigationLayout} rnd={0.7}>
<Route path="/" page={HomePage} name="home" />
<Route path="/about" page={AboutPage} name="about" />
<Route path="/multi-cell" page={MultiCellPage} name="multiCell" />

<Set wrap={ScaffoldLayout} title="EmptyUsers" titleTo="emptyUsers" buttonLabel="New EmptyUser" buttonTo="newEmptyUser">
<Route path="/empty-users/new" page={EmptyUserNewEmptyUserPage} name="newEmptyUser" />
{/* <Route path="/empty-users/{id:Int}/edit" page={EmptyUserEditEmptyUserPage} name="editEmptyUser" />
<Route path="/empty-users/{id:Int}" page={EmptyUserEmptyUserPage} name="emptyUser" /> */}
<Route path="/empty-users/{id:Int}/edit" page={EmptyUserEditEmptyUserPage} name="editEmptyUser" />
<Route path="/empty-users/{id:Int}" page={EmptyUserEmptyUserPage} name="emptyUser" />
<Route path="/empty-users" page={EmptyUserEmptyUsersPage} name="emptyUsers" />
</Set>

<Set wrap={ScaffoldLayout} title="UserExamples" titleTo="userExamples" buttonLabel="New UserExample" buttonTo="newUserExample">
<Route path="/user-examples/new" page={UserExampleNewUserExamplePage} name="newUserExample" />
{/* <Route path="/user-examples/{id:Int}/edit" page={UserExampleEditUserExamplePage} name="editUserExample" /> */}
<Route path="/user-examples/{id:Int}/edit" page={UserExampleEditUserExamplePage} name="editUserExample" />
<Route path="/user-examples/{id:Int}" page={UserExampleUserExamplePage} name="userExample" />
<Route path="/user-examples" page={UserExampleUserExamplesPage} name="userExamples" />
</Set>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import type { FindEmptyUsers, FindEmptyUsersVariables } from 'types/graphql'

import { Link, routes } from '@redwoodjs/router'
// TODO (RSC): Use Link from '@redwoodjs/router'
// import { Link, routes } from '@redwoodjs/router'
import { routes } from '@redwoodjs/router'
import type {
CellSuccessProps,
CellFailureProps,
Expand All @@ -11,6 +13,10 @@ import type {

import EmptyUsers from 'src/components/EmptyUser/EmptyUsers'

const Link = (props: any) => {
return <a href={props.to}>{props.children}</a>
}

export const QUERY: TypedDocumentNode<FindEmptyUsers, FindEmptyUsersVariables> =
gql`
query FindEmptyUsers {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'

import type { CellSuccessProps, CellFailureProps } from '@redwoodjs/web'

export const data = async () => {
const srcPath = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'..',
'..',
'..',
'src',
'components',
'ReadFileServerCell',
'ReadFileServerCell.tsx'
)

const file = fs.readFileSync(srcPath, 'utf-8')

return { file }
}

export const Loading = () => <div>Reading file...</div>

export const Empty = () => <div>Empty file</div>

export const Failure = ({ error }: CellFailureProps) => (
<div className="rw-cell-error">{error?.message}</div>
)

type SuccessProps = CellSuccessProps<Awaited<ReturnType<typeof data>>>
export const Success = ({ file }: SuccessProps) => {
return (
<div className="read-file-server-cell">
<p>The source of this server cell:</p>
<pre
style={{ border: '1px solid gray', margin: '1em', background: '#ddd' }}
>
<code>{file}</code>
</pre>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { TagDescriptor } from '@redwoodjs/web/dist/components/htmlTags'

import { Document } from './Document'
import ServerRoutes from './ServerRoutes'
import Routes from './Routes'

interface Props {
css: string[]
Expand All @@ -16,7 +16,7 @@ interface Props {
export const ServerEntry: React.FC<Props> = ({ css, meta, location }) => {
return (
<Document css={css} meta={meta}>
<ServerRoutes location={location} />
<Routes location={location} />
</Document>
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { namedRoutes as routes } from '@redwoodjs/router/dist/namedRoutes'

import ReadFileServerCell from 'src/components/ReadFileServerCell'

import './NavigationLayout.css'

type NavigationLayoutProps = {
Expand Down Expand Up @@ -34,6 +36,7 @@ const NavigationLayout = ({ children, rnd }: NavigationLayoutProps) => {
</ul>
</nav>
<div id="rnd">{Math.round(rnd * 100)}</div>
<ReadFileServerCell />
<p>Layout end</p>
<hr />
<main>{children}</main>
Expand Down
24 changes: 24 additions & 0 deletions packages/cli/src/commands/experimental/setupRscHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,30 @@ export const handler = async ({ force, verbose }) => {
},
options: { persistentOutput: true },
},
{
title: `Overwriting entry.client${ext}...`,
task: async () => {
const entryClientTemplate = fs.readFileSync(
path.resolve(
__dirname,
'templates',
'rsc',
'entry.client.tsx.template',
),
'utf-8',
)
const entryClientContent = isTypeScriptProject()
? entryClientTemplate
: await transformTSToJS(
rwPaths.web.entryClient,
entryClientTemplate,
)

writeFile(rwPaths.web.entryClient, entryClientContent, {
overwriteExisting: true,
})
},
},
{
title: `Overwriting entry.server${ext}...`,
task: async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { Link, routes } from '@redwoodjs/router'
import { namedRoutes as routes } from '@redwoodjs/router/dist/namedRoutes'

import './NavigationLayout.css'

const Link = (props: any) => {
return <a href={props.to}>{props.children}</a>
}

type NavigationLayoutProps = {
children?: React.ReactNode
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@
// 'src/pages/HomePage/HomePage.js' -> HomePage
// 'src/pages/Admin/BooksPage/BooksPage.js' -> AdminBooksPage

import { Router, Route, Set } from '@redwoodjs/router'
import { Route } from '@redwoodjs/router/dist/Route'
import { Set } from '@redwoodjs/router/dist/Set'
// @ts-expect-error - ESM issue. RW projects need to be ESM to properly pick up
// on the types here
import { Router } from '@redwoodjs/vite/Router'

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

const Routes = () => {
const Routes = ({ location }: { location?: any }) => {
return (
<Router>
<Router location={location}>
<Set wrap={NavigationLayout}>
<Route path="/" page={HomePage} name="home" />
<Route path="/about" page={AboutPage} name="about" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { hydrateRoot, createRoot } from 'react-dom/client'

import App from './App'
import Routes from './Routes'

/**
* When `#redwood-app` isn't empty then it's very likely that you're using
* pre-rendering. So React attaches event listeners to the existing markup
* rather than replacing it.
* https://react.dev/reference/react-dom/client/hydrateRoot
*/
const redwoodAppElement = document.getElementById('redwood-app')

if (!redwoodAppElement) {
throw new Error(
"Could not find an element with ID 'redwood-app'. Please ensure it " +
"exists in your 'web/src/index.html' file."
)
}

if (redwoodAppElement.children?.length > 0) {
hydrateRoot(
redwoodAppElement,
<App>
<Routes />
</App>
)
} else {
const root = createRoot(redwoodAppElement)
root.render(
<App>
<Routes />
</App>
)
}
Loading

0 comments on commit 5adb761

Please sign in to comment.