Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(client-entry): Slight tweaks around entry.client handling #10741

Merged
merged 4 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/vite/src/rsc/rscBuildClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export async function rscBuildClient(clientEntryFiles: Record<string, string>) {
input: {
// @MARK: temporary hack to find the entry client so we can get the
// index.css bundle but we don't actually want this on an rsc page!
'rwjs-client-entry': rwPaths.web.entryClient,
__rwjs__client_entry: rwPaths.web.entryClient,
// we need this, so that the output contains rsc-specific bundles
// for the client-only components. They get loaded once the page is
// rendered
Expand Down
2 changes: 1 addition & 1 deletion packages/vite/src/rsc/rscBuildForSsr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export async function rscBuildForSsr({
// index.css bundle but we don't actually want this on an rsc page!
// TODO (RSC): Look into if we can remove this (and perhaps instead
// use entry.server)
'rwjs-client-entry': rwPaths.web.entryClient,
__rwjs__client_entry: rwPaths.web.entryClient,
'entry.server': rwPaths.web.entryServer,
// we need this, so that the output contains rsc-specific bundles
// for the client-only components. They get loaded once the page is
Expand Down
40 changes: 24 additions & 16 deletions packages/vite/src/runFeServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,29 @@ export async function runFeServer() {
await import(clientBuildManifestUrl, { with: { type: 'json' } })
).default

// @MARK: Surely there's a better way than this!
const clientEntry = Object.values(clientBuildManifest).find(
(manifestItem) => {
// For RSC builds, we pass in many Vite entries, so we need to find it differently.
return rscEnabled
? manifestItem.file.includes('rwjs-client-entry-')
: manifestItem.isEntry
},
)
// Even though `entry.server.tsx` is the main entry point for SSR, we still
// need to read the client build manifest and find `entry.client.tsx` to get
// the correct links to insert for the initial CSS files that will eventually
// be rendered when the finalized html output is being streamed to the
// browser. We also need it to tell React what JS bundle contains
// `hydrateRoot` when it'll eventually get to hydrating things in the browser
//
// So, `clientEntry` is used to find the initial JS bundle to load in the
// browser and also to discover CSS files that will be needed to render the
// initial page.
//
// In addition to all the above the discovered CSS files are also passed to
// all middleware that have been registered
const clientEntry = rscEnabled
? clientBuildManifest['entry.client.tsx'] ||
clientBuildManifest['entry.client.jsx']
: Object.values(clientBuildManifest).find(
(manifestItem) => manifestItem.isEntry,
)

if (!clientEntry) {
throw new Error('Could not find client entry in build manifest')
}

// @MARK: In prod, we create it once up front!
const middlewareRouter = await createMiddlewareRouter()
Expand All @@ -111,10 +125,6 @@ export async function runFeServer() {
})
}

if (!clientEntry) {
throw new Error('Could not find client entry in build manifest')
}

// 1. Use static handler for assets
// For CF workers, we'd need an equivalent of this
app.use(
Expand Down Expand Up @@ -166,15 +176,13 @@ export async function runFeServer() {
// the static assets over any application routing.
app.use(express.static(rwPaths.web.distClient, { index: false }))

const clientEntryPath = '/' + clientEntry.file

const getStylesheetLinks = rscEnabled
? getRscStylesheetLinkGenerator(clientEntry.css)
: () => clientEntry.css || []

const routeHandler = await createReactStreamingHandler({
routes: Object.values(routeManifest),
clientEntryPath,
clientEntryPath: clientEntry.file,
getStylesheetLinks,
getMiddlewareRouter: async () => middlewareRouter,
})
Expand Down
25 changes: 13 additions & 12 deletions packages/vite/src/streaming/createReactStreamingHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,19 @@ export const createReactStreamingHandler = async (
route.pathDefinition,
currentUrl.pathname,
)

if (match) {
currentRoute = route
parsedParams = rest

break
}
}

// Using a function to get the CSS links because we need to wait for the
// vite dev server to analyze the module graph
const cssLinks = getStylesheetLinks(currentRoute)

// ~~~ Middleware Handling ~~~
if (middlewareRouter) {
const matchedMw = middlewareRouter.find(req.method as HTTPMethod, req.url)
Expand All @@ -107,7 +113,7 @@ export const createReactStreamingHandler = async (
matchedMw?.handler as Middleware | undefined,
{
route: currentRoute,
cssPaths: getStylesheetLinks(currentRoute),
cssPaths: cssLinks,
params: matchedMw?.params,
viteDevServer,
},
Expand Down Expand Up @@ -172,20 +178,15 @@ export const createReactStreamingHandler = async (

metaTags = routeHookOutput.meta

// @MARK @TODO(RSC_DC): the entry path for RSC will be different,
// because we don't want to inject a full bundle, just a slice of it
// I'm not sure what though....
const jsBundles = [
clientEntryPath, // @NOTE: must have slash in front
currentRoute.bundle && '/' + currentRoute.bundle,
].filter(Boolean) as string[]
// TODO (RSC): Do we really want to inject the full bundle here, or is
// there a smaller slice of it we can inject?
const jsBundles = ['/' + clientEntryPath]
if (currentRoute.bundle) {
jsBundles.push('/' + currentRoute.bundle)
}

const isSeoCrawler = isbot(req.headers.get('user-agent') || '')

// Using a function to get the CSS links because we need to wait for the
// vite dev server to analyze the module graph
const cssLinks = getStylesheetLinks(currentRoute)

const reactResponse = await reactRenderToStreamResponse(
mwResponse,
{
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/streaming/streamHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ export async function reactRenderToStreamResponse(
clearTimeout(timeoutHandle)
}
}

function applyStreamTransforms(
reactStream: ReactDOMServerReadableStream,
transformsToApply: (TransformStream | false)[],
Expand Down
Loading