-
Notifications
You must be signed in to change notification settings - Fork 993
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
experimental feature flag for rsc (#8837)
- Loading branch information
Showing
11 changed files
with
258 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers' | ||
|
||
import { getEpilogue } from './util' | ||
|
||
export const command = 'setup-rsc' | ||
|
||
export const description = 'Enable React Server Components (RSC)' | ||
|
||
export const EXPERIMENTAL_TOPIC_ID = 5081 | ||
|
||
export const builder = (yargs) => { | ||
yargs | ||
.option('force', { | ||
alias: 'f', | ||
default: false, | ||
description: 'Overwrite existing configuration', | ||
type: 'boolean', | ||
}) | ||
.epilogue(getEpilogue(command, description, EXPERIMENTAL_TOPIC_ID, true)) | ||
} | ||
|
||
export const handler = async (options) => { | ||
recordTelemetryAttributes({ | ||
command: ['experimental', command].join(' '), | ||
force: options.force, | ||
}) | ||
const { handler } = await import('./setupRscHandler.js') | ||
return handler(options) | ||
} |
157 changes: 157 additions & 0 deletions
157
packages/cli/src/commands/experimental/setupRscHandler.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import fs from 'fs' | ||
import path from 'path' | ||
|
||
import { Listr } from 'listr2' | ||
|
||
import { getConfig, getConfigPath } from '@redwoodjs/project-config' | ||
import { errorTelemetry } from '@redwoodjs/telemetry' | ||
|
||
import { getPaths, writeFile } from '../../lib' | ||
import c from '../../lib/colors' | ||
import { isTypeScriptProject } from '../../lib/project' | ||
|
||
import { | ||
command, | ||
description, | ||
EXPERIMENTAL_TOPIC_ID, | ||
} from './setupStreamingSsr' | ||
import { printTaskEpilogue } from './util' | ||
|
||
export const handler = async ({ force, verbose }) => { | ||
const rwPaths = getPaths() | ||
const redwoodTomlPath = getConfigPath() | ||
const configContent = fs.readFileSync(redwoodTomlPath, 'utf-8') | ||
|
||
const tasks = new Listr( | ||
[ | ||
{ | ||
title: 'Check prerequisites', | ||
task: () => { | ||
if (!rwPaths.web.entryClient || !rwPaths.web.viteConfig) { | ||
throw new Error('Vite needs to be setup before you can enable RSCs') | ||
} | ||
|
||
if (!getConfig().experimental?.streamingSsr?.enabled) { | ||
throw new Error( | ||
'The Streaming SSR experimental feature must be enabled before you can enable RSCs' | ||
) | ||
} | ||
|
||
if (!isTypeScriptProject()) { | ||
throw new Error( | ||
'RSCs are only supported in TypeScript projects at this time' | ||
) | ||
} | ||
}, | ||
}, | ||
{ | ||
title: 'Adding config to redwood.toml...', | ||
task: (_ctx, task) => { | ||
if (!configContent.includes('[experimental.rsc]')) { | ||
writeFile( | ||
redwoodTomlPath, | ||
configContent.concat('\n[experimental.rsc]\n enabled = true\n'), | ||
{ | ||
overwriteExisting: true, // redwood.toml always exists | ||
} | ||
) | ||
} else { | ||
if (force) { | ||
task.output = 'Overwriting config in redwood.toml' | ||
|
||
writeFile( | ||
redwoodTomlPath, | ||
configContent.replace( | ||
// Enable if it's currently disabled | ||
'\n[experimental.rsc]\n enabled = false\n', | ||
'\n[experimental.rsc]\n enabled = true\n' | ||
), | ||
{ | ||
overwriteExisting: true, // redwood.toml always exists | ||
} | ||
) | ||
} else { | ||
task.skip( | ||
'The [experimental.rsc] config block already exists in your `redwood.toml` file.' | ||
) | ||
} | ||
} | ||
}, | ||
options: { persistentOutput: true }, | ||
}, | ||
{ | ||
title: 'Adding entries.ts...', | ||
task: async () => { | ||
const entriesTemplate = fs.readFileSync( | ||
path.resolve(__dirname, 'templates', 'rsc', 'entries.ts.template'), | ||
'utf-8' | ||
) | ||
const entriesPath = path.join(rwPaths.web.src, 'entries.ts') | ||
|
||
writeFile(entriesPath, entriesTemplate, { | ||
overwriteExisting: force, | ||
}) | ||
}, | ||
}, | ||
{ | ||
title: 'Updating App.tsx...', | ||
task: async () => { | ||
const appTemplate = fs.readFileSync( | ||
path.resolve(__dirname, 'templates', 'rsc', 'App.tsx.template'), | ||
'utf-8' | ||
) | ||
const appPath = rwPaths.web.app | ||
|
||
writeFile(appPath, appTemplate, { | ||
overwriteExisting: true, | ||
}) | ||
}, | ||
}, | ||
{ | ||
title: 'Adding Counter.tsx...', | ||
task: async () => { | ||
const counterTemplate = fs.readFileSync( | ||
path.resolve(__dirname, 'templates', 'rsc', 'Counter.tsx.template'), | ||
'utf-8' | ||
) | ||
const counterPath = path.join(rwPaths.web.src, 'Counter.tsx') | ||
|
||
writeFile(counterPath, counterTemplate, { | ||
overwriteExisting: force, | ||
}) | ||
}, | ||
}, | ||
{ | ||
title: 'Updating index.html...', | ||
task: async () => { | ||
let indexHtml = fs.readFileSync(rwPaths.web.html, 'utf-8') | ||
indexHtml = indexHtml.replace( | ||
'href="/favicon.png" />', | ||
'href="/favicon.png" />\n <script type="module" src="entry.client.tsx"></script>' | ||
) | ||
|
||
writeFile(rwPaths.web.html, indexHtml, { | ||
overwriteExisting: true, | ||
}) | ||
}, | ||
}, | ||
{ | ||
task: () => { | ||
printTaskEpilogue(command, description, EXPERIMENTAL_TOPIC_ID) | ||
}, | ||
}, | ||
], | ||
{ | ||
rendererOptions: { collapseSubtasks: false, persistentOutput: true }, | ||
renderer: verbose ? 'verbose' : 'default', | ||
} | ||
) | ||
|
||
try { | ||
await tasks.run() | ||
} catch (e) { | ||
errorTelemetry(process.argv, e.message) | ||
console.error(c.error(e.message)) | ||
process.exit(e?.exitCode || 1) | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
packages/cli/src/commands/experimental/templates/rsc/App.tsx.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Counter } from './Counter' | ||
|
||
const App = ({ name = 'Anonymous' }) => { | ||
return ( | ||
<div style={{ border: '3px red dashed', margin: '1em', padding: '1em' }}> | ||
<h1>Hello {name}!!</h1> | ||
<h3>This is a server component.</h3> | ||
<Counter /> | ||
</div> | ||
) | ||
} | ||
|
||
export default App |
15 changes: 15 additions & 0 deletions
15
packages/cli/src/commands/experimental/templates/rsc/Counter.tsx.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
'use client' | ||
|
||
import React from 'react' | ||
|
||
export const Counter = () => { | ||
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>This is a client component.</h3> | ||
</div> | ||
) | ||
} |
25 changes: 25 additions & 0 deletions
25
packages/cli/src/commands/experimental/templates/rsc/entries.ts.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
export type GetEntry = (rscId: string) => Promise< | ||
| React.FunctionComponent | ||
| { | ||
default: React.FunctionComponent | ||
} | ||
| null | ||
> | ||
|
||
export function defineEntries(getEntry: GetEntry) { | ||
return { | ||
getEntry, | ||
} | ||
} | ||
|
||
export default defineEntries( | ||
// getEntry | ||
async (id) => { | ||
switch (id) { | ||
case 'App': | ||
return import('./App') | ||
default: | ||
return null | ||
} | ||
} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters