Skip to content

Commit

Permalink
RSC: Add RW env var definitions to Vite config and include FatalError…
Browse files Browse the repository at this point in the history
…Boundary (#9622)
  • Loading branch information
Tobbe authored Dec 5, 2023
1 parent 05bc41c commit 69a1770
Show file tree
Hide file tree
Showing 19 changed files with 321 additions and 61 deletions.
20 changes: 20 additions & 0 deletions __fixtures__/test-project-rsa/web/src/AboutCounter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use client'

import React from 'react'

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

export const AboutCounter = () => {
const [count, setCount] = React.useState(0)

return (
<div style={{ border: '3px blue dashed', margin: '1em', padding: '1em' }}>
<p>Count: {count}</p>
<button onClick={() => setCount((c) => c + 1)}>Increment</button>
<h3 className={styles.header}>This is a client component.</h3>
<p>RSC on client: {globalThis.RWJS_EXP_RSC ? 'enabled' : 'disabled'}</p>
</div>
)
}
5 changes: 3 additions & 2 deletions __fixtures__/test-project-rsa/web/src/AboutPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Assets } from '@redwoodjs/vite/assets'
import { ProdRwRscServerGlobal } from '@redwoodjs/vite/rwRscGlobal'

import { Counter } from './Counter'
import { AboutCounter } from './AboutCounter'

import './AboutPage.css'

Expand All @@ -17,7 +17,8 @@ const AboutPage = () => {
<Assets />
<div style={{ border: '3px red dashed', margin: '1em', padding: '1em' }}>
<h1>About Redwood</h1>
<Counter />
<AboutCounter />
<p>RSC on server: {globalThis.RWJS_EXP_RSC ? 'enabled' : 'disabled'}</p>
</div>
</div>
)
Expand Down
18 changes: 11 additions & 7 deletions __fixtures__/test-project-rsa/web/src/entry.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { createRoot } from 'react-dom/client'

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

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

const redwoodAppElement = document.getElementById('redwood-app')
Expand All @@ -15,13 +17,15 @@ const root = createRoot(redwoodAppElement)

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>
<FatalErrorBoundary page={FatalErrorPage}>
<Router>
<Set wrap={NavigationLayout}>
<Route path="/" page={HomePage} name="home" />
<Route path="/about" page={AboutPage} name="about" />
</Set>
<Route notfound page={NotFoundPage} />
</Router>
</FatalErrorBoundary>
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use client'

import React from 'react'

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

export const AboutCounter = () => {
const [count, setCount] = React.useState(0)

return (
<div style={{ border: '3px blue dashed', margin: '1em', padding: '1em' }}>
<p>Count: {count}</p>
<button onClick={() => setCount((c) => c + 1)}>Increment</button>
<h3 className={styles.header}>This is a client component.</h3>
<p>RSC on client: {globalThis.RWJS_EXP_RSC ? 'enabled' : 'disabled'}</p>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Assets } from '@redwoodjs/vite/assets'
import { ProdRwRscServerGlobal } from '@redwoodjs/vite/rwRscGlobal'

import { Counter } from './Counter'
import { AboutCounter } from './AboutCounter'

import './AboutPage.css'

Expand All @@ -17,7 +17,8 @@ const AboutPage = () => {
<Assets />
<div style={{ border: '3px red dashed', margin: '1em', padding: '1em' }}>
<h1>About Redwood</h1>
<Counter />
<AboutCounter />
<p>RSC on server: {globalThis.RWJS_EXP_RSC ? 'enabled' : 'disabled'}</p>
</div>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { createRoot } from 'react-dom/client'

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

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

const redwoodAppElement = document.getElementById('redwood-app')
Expand All @@ -15,13 +17,15 @@ const root = createRoot(redwoodAppElement)

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>
<FatalErrorBoundary page={FatalErrorPage}>
<Router>
<Set wrap={NavigationLayout}>
<Route path="/" page={HomePage} name="home" />
<Route path="/about" page={AboutPage} name="about" />
</Set>
<Route notfound page={NotFoundPage} />
</Router>
</FatalErrorBoundary>
)
}

Expand Down
19 changes: 19 additions & 0 deletions packages/cli/src/commands/experimental/setupRscHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,25 @@ export const handler = async ({ force, verbose }) => {
})
},
},
{
title: 'Adding AboutCounter.tsx...',
task: async () => {
const counterTemplate = fs.readFileSync(
path.resolve(
__dirname,
'templates',
'rsc',
'AboutCounter.tsx.template'
),
'utf-8'
)
const counterPath = path.join(rwPaths.web.src, 'AboutCounter.tsx')

writeFile(counterPath, counterTemplate, {
overwriteExisting: force,
})
},
},
{
title: 'Adding CSS files...',
task: async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use client'

import React from 'react'

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

export const AboutCounter = () => {
const [count, setCount] = React.useState(0)

return (
<div style={{ border: '3px blue dashed', margin: '1em', padding: '1em' }}>
<p>Count: {count}</p>
<button onClick={() => setCount((c) => c + 1)}>Increment</button>
<h3 className={styles.header}>This is a client component.</h3>
<p>RSC on client: {globalThis.RWJS_EXP_RSC ? 'enabled' : 'disabled'}</p>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Assets } from '@redwoodjs/vite/assets'
import { ProdRwRscServerGlobal } from '@redwoodjs/vite/rwRscGlobal'

import { Counter } from './Counter'
import { AboutCounter } from './AboutCounter'

import './AboutPage.css'

Expand All @@ -17,7 +17,8 @@ const AboutPage = () => {
<Assets />
<div style={{ border: '3px red dashed', margin: '1em', padding: '1em' }}>
<h1>About Redwood</h1>
<Counter />
<AboutCounter />
<p>RSC on server: {globalThis.RWJS_EXP_RSC ? 'enabled' : 'disabled'}</p>
</div>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { createRoot } from 'react-dom/client'

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

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

const redwoodAppElement = document.getElementById('redwood-app')
Expand All @@ -15,13 +17,15 @@ const root = createRoot(redwoodAppElement)

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>
<FatalErrorBoundary page={FatalErrorPage}>
<Router>
<Set wrap={NavigationLayout}>
<Route path="/" page={HomePage} name="home" />
<Route path="/about" page={AboutPage} name="about" />
</Set>
<Route notfound page={NotFoundPage} />
</Router>
</FatalErrorBoundary>
)
}

Expand Down
1 change: 0 additions & 1 deletion packages/vite/src/buildFeServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export const buildFeServer = async ({ verbose, webDir }: BuildOptions = {}) => {

await buildRscFeServer({
viteConfigPath,
webSrc: rwPaths.web.src,
webHtml: rwPaths.web.html,
entries: rwPaths.web.entries,
webDist: rwPaths.web.dist,
Expand Down
7 changes: 4 additions & 3 deletions packages/vite/src/buildRscFeServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { rscBuildAnalyze } from './rsc/rscBuildAnalyze'
import { rscBuildClient } from './rsc/rscBuildClient'
import { rscBuildClientEntriesMappings } from './rsc/rscBuildClientEntriesFile'
import { rscBuildCopyCssAssets } from './rsc/rscBuildCopyCssAssets'
import { rscBuildRwEnvVars } from './rsc/rscBuildRwEnvVars'
import { rscBuildServer } from './rsc/rscBuildServer'

interface Args {
viteConfigPath: string
webSrc: string
webHtml: string
entries: string
webDist: string
Expand All @@ -16,7 +16,6 @@ interface Args {

export const buildRscFeServer = async ({
viteConfigPath,
webSrc,
webHtml,
entries,
webDist,
Expand All @@ -30,7 +29,6 @@ export const buildRscFeServer = async ({

// Generate the client bundle
const clientBuildOutput = await rscBuildClient(
webSrc,
webHtml,
webDist,
clientEntryFiles
Expand All @@ -54,4 +52,7 @@ export const buildRscFeServer = async ({
clientEntryFiles,
webDistServerEntries
)

// Mappings from server to client asset file names
await rscBuildRwEnvVars(webDistServerEntries)
}
1 change: 1 addition & 0 deletions packages/vite/src/react-server-dom-webpack/node-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ export async function load(
url,
defaultLoad
)

return {
format: 'module',
source: newSrc,
Expand Down
58 changes: 56 additions & 2 deletions packages/vite/src/rsc/rscBuildClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import path from 'node:path'

import react from '@vitejs/plugin-react'
import { build as viteBuild } from 'vite'

import { getConfig, getPaths } from '@redwoodjs/project-config'

import { onWarn } from '../lib/onWarn'
import { rscIndexPlugin } from '../waku-lib/vite-plugin-rsc'

Expand All @@ -10,14 +14,64 @@ import { rscIndexPlugin } from '../waku-lib/vite-plugin-rsc'
* Generate the client bundle
*/
export async function rscBuildClient(
webSrc: string,
webHtml: string,
webDist: string,
clientEntryFiles: Record<string, string>
) {
const rwPaths = getPaths()
const rwConfig = getConfig()

const graphQlUrl =
rwConfig.web.apiGraphQLUrl ?? rwConfig.web.apiUrl + '/graphql'

const clientBuildOutput = await viteBuild({
// configFile: viteConfigPath,
root: webSrc,
root: rwPaths.web.src,
envPrefix: 'REDWOOD_ENV_',
publicDir: path.join(rwPaths.web.base, 'public'),
define: {
RWJS_ENV: {
__REDWOOD__APP_TITLE: rwConfig.web.title || path.basename(rwPaths.base),
RWJS_API_GRAPHQL_URL: graphQlUrl,
RWJS_API_URL: rwConfig.web.apiUrl,
RWJS_EXP_STREAMING_SSR: rwConfig.experimental?.streamingSsr?.enabled,
RWJS_EXP_RSC: rwConfig.experimental?.rsc?.enabled,
},
RWJS_DEBUG_ENV: {
RWJS_SRC_ROOT: rwPaths.web.src,
REDWOOD_ENV_EDITOR: JSON.stringify(process.env.REDWOOD_ENV_EDITOR),
},
// Vite can automatically expose environment variables, but we
// disable that in `buildFeServer.ts` by setting `envFile: false`
// because we want to use our own logic for loading .env,
// .env.defaults, etc
// The two object spreads below will expose all environment
// variables listed in redwood.toml and all environment variables
// prefixed with REDWOOD_ENV_
...Object.fromEntries(
rwConfig.web.includeEnvironmentVariables.flatMap((envName) => [
// TODO (RSC): Figure out if/why we need to disable eslint here.
// Re-enable if possible
// eslint-disable-next-line
[`import.meta.env.${envName}`, JSON.stringify(process.env[envName])],
// TODO (RSC): Figure out if/why we need to disable eslint here
// Re-enable if possible
// eslint-disable-next-line
[`process.env.${envName}`, JSON.stringify(process.env[envName])],
])
),
...Object.entries(process.env).reduce<Record<string, any>>(
(acc, [key, value]) => {
if (key.startsWith('REDWOOD_ENV_')) {
acc[`import.meta.env.${key}`] = JSON.stringify(value)
acc[`process.env.${key}`] = JSON.stringify(value)
}

return acc
},
{}
),
},
plugins: [react(), rscIndexPlugin()],
build: {
outDir: webDist,
Expand Down
Loading

0 comments on commit 69a1770

Please sign in to comment.