From 565f62000b327df732b7b7040a1419852225a7d9 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Thu, 29 Jun 2023 08:34:37 +0200 Subject: [PATCH] React Streaming and SSR feature flag (#8764) --- .../experimental/setupStreamingSsr.js | 30 +++++++++++ .../experimental/setupStreamingSsrHandler.js | 54 +++++++++++++++++++ .../src/__tests__/config.test.ts | 3 ++ packages/project-config/src/config.ts | 6 +++ packages/vite/src/index.ts | 3 ++ packages/web/ambient.d.ts | 3 ++ packages/web/src/config.ts | 1 + 7 files changed, 100 insertions(+) create mode 100644 packages/cli/src/commands/experimental/setupStreamingSsr.js create mode 100644 packages/cli/src/commands/experimental/setupStreamingSsrHandler.js diff --git a/packages/cli/src/commands/experimental/setupStreamingSsr.js b/packages/cli/src/commands/experimental/setupStreamingSsr.js new file mode 100644 index 000000000000..38b8ff203244 --- /dev/null +++ b/packages/cli/src/commands/experimental/setupStreamingSsr.js @@ -0,0 +1,30 @@ +import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers' + +import { getEpilogue } from './util' + +export const command = 'setup-streaming-ssr' + +export const description = + 'Enable React Streaming and Server Side Rendering (SSR)' + +export const EXPERIMENTAL_TOPIC_ID = 5052 + +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('./setupStreamingSsrHandler.js') + return handler(options) +} diff --git a/packages/cli/src/commands/experimental/setupStreamingSsrHandler.js b/packages/cli/src/commands/experimental/setupStreamingSsrHandler.js new file mode 100644 index 000000000000..dac1a0948e86 --- /dev/null +++ b/packages/cli/src/commands/experimental/setupStreamingSsrHandler.js @@ -0,0 +1,54 @@ +import fs from 'fs' + +import { getConfigPath } from '@redwoodjs/project-config' + +import { writeFile } from '../../lib' + +import { + command, + description, + EXPERIMENTAL_TOPIC_ID, +} from './setupStreamingSsr' +import { printTaskEpilogue } from './util' + +export const handler = async ({ force }) => { + const redwoodTomlPath = getConfigPath() + const configContent = fs.readFileSync(redwoodTomlPath, 'utf-8') + + if (!configContent.includes('[experimental.streamingSsr]')) { + console.log('Adding config to redwood.toml...') + + // Use string replace to preserve comments and formatting + writeFile( + redwoodTomlPath, + configContent.concat(`\n[experimental.streamingSsr]\n enabled = true\n`), + { + overwriteExisting: true, // redwood.toml always exists + } + ) + } else { + if (force) { + console.log('Updating config in redwood.toml...') + writeFile( + redwoodTomlPath, + configContent.replace( + // Enable if it's currently disabled + `\n[experimental.streamingSsr]\n enabled = false\n`, + `\n[experimental.streamingSsr]\n enabled = true\n` + ), + { + overwriteExisting: true, // redwood.toml always exists + } + ) + } else { + console.log('Adding config to redwood.toml...') + console.log( + " The [experimental.studio] config block already exists in your 'redwood.toml' file." + ) + } + } + + console.log() + + printTaskEpilogue(command, description, EXPERIMENTAL_TOPIC_ID) +} diff --git a/packages/project-config/src/__tests__/config.test.ts b/packages/project-config/src/__tests__/config.test.ts index 40c233a09a9b..e0dac47ddc45 100644 --- a/packages/project-config/src/__tests__/config.test.ts +++ b/packages/project-config/src/__tests__/config.test.ts @@ -55,6 +55,9 @@ describe('getConfig', () => { "apiSdk": undefined, "enabled": false, }, + "streamingSsr": { + "enabled": false, + }, "studio": { "graphiql": { "authImpersonation": { diff --git a/packages/project-config/src/config.ts b/packages/project-config/src/config.ts index 29fddc4a9f76..a0544b9d1b0d 100644 --- a/packages/project-config/src/config.ts +++ b/packages/project-config/src/config.ts @@ -104,6 +104,9 @@ export interface Config { plugins: CLIPlugin[] } useSDLCodeGenForGraphQLTypes: boolean + streamingSsr: { + enabled: boolean + } } } @@ -177,6 +180,9 @@ const DEFAULT_CONFIG: Config = { ], }, useSDLCodeGenForGraphQLTypes: false, + streamingSsr: { + enabled: false, + }, }, } diff --git a/packages/vite/src/index.ts b/packages/vite/src/index.ts index c178d804c368..939c81b4a350 100644 --- a/packages/vite/src/index.ts +++ b/packages/vite/src/index.ts @@ -99,6 +99,9 @@ export default function redwoodPluginVite(): PluginOption[] { RWJS_API_URL: rwConfig.web.apiUrl, __REDWOOD__APP_TITLE: rwConfig.web.title || path.basename(rwPaths.base), + RWJS_EXP_STREAMING_SSR: + rwConfig.experimental.streamingSsr && + rwConfig.experimental.streamingSsr.enabled, }, RWJS_DEBUG_ENV: { RWJS_SRC_ROOT: rwPaths.web.src, diff --git a/packages/web/ambient.d.ts b/packages/web/ambient.d.ts index 6ad26f3c084b..e3cf88ff7aeb 100644 --- a/packages/web/ambient.d.ts +++ b/packages/web/ambient.d.ts @@ -13,6 +13,7 @@ declare global { RWJS_API_GRAPHQL_URL: string /** URL or absolute path to serverless functions */ RWJS_API_URL: string + RWJS_EXP_STREAMING_SSR: boolean __REDWOOD__APP_TITLE: string __REDWOOD__APOLLO_STATE: NormalizedCacheObject @@ -31,6 +32,8 @@ declare global { var RWJS_API_URL: string /** Path to Redwood app source used by Development Error page to resolve source code paths */ var RWJS_SRC_ROOT: string + /** Flag for experimental Streaming and SSR support */ + var RWJS_EXP_STREAMING_SSR: boolean namespace NodeJS { interface Global { diff --git a/packages/web/src/config.ts b/packages/web/src/config.ts index 73612f83aeaf..dcb5f237ecd9 100644 --- a/packages/web/src/config.ts +++ b/packages/web/src/config.ts @@ -5,3 +5,4 @@ globalThis.RWJS_API_GRAPHQL_URL = RWJS_ENV.RWJS_API_GRAPHQL_URL as string globalThis.RWJS_API_URL = RWJS_ENV.RWJS_API_URL as string globalThis.__REDWOOD__APP_TITLE = RWJS_ENV.__REDWOOD__APP_TITLE as string +globalThis.RWJS_EXP_STREAMING_SSR = RWJS_ENV.RWJS_EXP_STREAMING_SSR as boolean