From 404aa107667a96927eada4cd1ec6c523bc31448b Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Thu, 30 Nov 2023 10:59:33 +0100 Subject: [PATCH] RSC: Handle direct navigation to pages other than / --- packages/vite/src/runFeServer.ts | 47 ++++++++++++------- .../streaming/createReactStreamingHandler.ts | 24 ++++++++-- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/packages/vite/src/runFeServer.ts b/packages/vite/src/runFeServer.ts index 6810fa9212e5..6e0168a63ec3 100644 --- a/packages/vite/src/runFeServer.ts +++ b/packages/vite/src/runFeServer.ts @@ -127,37 +127,50 @@ export async function runFeServer() { const getStylesheetLinks = () => indexEntry.css || [] const clientEntry = '/' + indexEntry.file - if (!rwConfig.experimental?.rsc?.enabled) { - for (const route of Object.values(routeManifest)) { + for (const route of Object.values(routeManifest)) { + // if it is a 404, register it at the end somehow. + if (!route.matchRegexString) { + continue + } + + // @TODO: we don't need regexes here + // Param matching, etc. all handled within the route handler now + const expressPathDef = route.hasParams + ? route.matchRegexString + : route.pathDefinition + + if (!getConfig().experimental?.rsc?.enabled) { const routeHandler = await createReactStreamingHandler({ route, clientEntryPath: clientEntry, getStylesheetLinks, }) - // if it is a 404, register it at the end somehow. - if (!route.matchRegexString) { - continue - } - - // @TODO: we don't need regexes here - // Param matching, etc. all handled within the route handler now - const expressPathDef = route.hasParams - ? route.matchRegexString - : route.pathDefinition - // Wrap with whatg/server adapter. Express handler -> Fetch API handler app.get(expressPathDef, createServerAdapter(routeHandler)) + } else { + console.log('expressPathDef', expressPathDef) + + // This is for RSC only. And only for now, until we have SSR working we + // with RSC. This maps /, /about, etc to index.html + app.get(expressPathDef, (req, res, next) => { + // Serve index.html for all routes, to let client side routing take + // over + req.url = '/' + // Without this, we get a flash of a url with a trailing slash. Still + // works, but doesn't look nice + // For example, if we navigate to /about we'll see a flash of /about/ + // before returning to /about + req.originalUrl = '/' + + return express.static(rwPaths.web.dist)(req, res, next) + }) } } // Mounting middleware at /rw-rsc will strip /rw-rsc from req.url app.use('/rw-rsc', createRscRequestHandler()) - // This is basically the route for / -> HomePage. Used by RSC - // Using .get() here to get exact path matching - app.get('/', express.static(rwPaths.web.dist)) - app.listen(rwConfig.web.port) console.log( `Started production FE server on http://localhost:${rwConfig.web.port}` diff --git a/packages/vite/src/streaming/createReactStreamingHandler.ts b/packages/vite/src/streaming/createReactStreamingHandler.ts index 2fd3356dc747..9b58e126a561 100644 --- a/packages/vite/src/streaming/createReactStreamingHandler.ts +++ b/packages/vite/src/streaming/createReactStreamingHandler.ts @@ -4,7 +4,7 @@ import isbot from 'isbot' import type { ViteDevServer } from 'vite' import type { RWRouteManifestItem } from '@redwoodjs/internal' -import { getAppRouteHook, getPaths } from '@redwoodjs/project-config' +import { getAppRouteHook, getConfig, getPaths } from '@redwoodjs/project-config' import { matchPath } from '@redwoodjs/router' import type { TagDescriptor } from '@redwoodjs/web' @@ -37,10 +37,24 @@ export const createReactStreamingHandler = async ( let fallbackDocumentImport: any if (isProd) { - entryServerImport = await import(makeFilePath(rwPaths.web.distEntryServer)) - fallbackDocumentImport = await import( - makeFilePath(rwPaths.web.distDocumentServer) - ) + // TODO (RSC) Consolidate paths, so we can have the same code for SSR and RSC + if (getConfig().experimental?.rsc?.enabled) { + entryServerImport = await import( + makeFilePath( + path.join(rwPaths.web.distServer, 'assets', 'entry.server.js') + ) + ) + fallbackDocumentImport = await import( + makeFilePath(path.join(rwPaths.web.distServer, 'assets', 'Document.js')) + ) + } else { + entryServerImport = await import( + makeFilePath(rwPaths.web.distEntryServer) + ) + fallbackDocumentImport = await import( + makeFilePath(rwPaths.web.distDocumentServer) + ) + } } // @NOTE: we are returning a FetchAPI handler