Skip to content

Commit 7543b1b

Browse files
authored
fix(rsc): Make SSR work when there are module level server actions (#11728)
1 parent 4e614a9 commit 7543b1b

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

packages/vite/ambient.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ declare global {
2727
var __rwjs__vite_ssr_runtime: ViteRuntime | undefined
2828
var __rwjs__vite_rsc_runtime: ViteRuntime | undefined
2929
var __rwjs__client_references: Set<string> | undefined
30+
var __rwjs__server_references: Set<string> | undefined
3031

3132
var __REDWOOD__HELMET_CONTEXT: { helmet?: HelmetServerState }
3233

packages/vite/src/devFeServer.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { createMiddlewareRouter } from './middleware/register.js'
2323
import { rscRoutesAutoLoader } from './plugins/vite-plugin-rsc-routes-auto-loader.js'
2424
import { rscRoutesImports } from './plugins/vite-plugin-rsc-routes-imports.js'
2525
import { rscSsrRouterImport } from './plugins/vite-plugin-rsc-ssr-router-import.js'
26+
import { rscTransformUseServerPlugin } from './plugins/vite-plugin-rsc-transform-server.js'
2627
import { createWebSocketServer } from './rsc/rscWebSocketServer.js'
2728
import { collectCssPaths, componentsModules } from './streaming/collectCss.js'
2829
import { createReactStreamingHandler } from './streaming/createReactStreamingHandler.js'
@@ -183,6 +184,7 @@ async function createServer() {
183184
globalThis.__rwjs__vite_ssr_runtime =
184185
await createViteRuntime(viteSsrDevServer)
185186
globalThis.__rwjs__client_references = new Set<string>()
187+
globalThis.__rwjs__server_references = new Set<string>()
186188

187189
// const clientEntryFileSet = new Set<string>()
188190
// const serverEntryFileSet = new Set<string>()
@@ -258,7 +260,23 @@ async function createServer() {
258260
'busboy',
259261
'cookie',
260262
],
261-
// exclude: ['webpack']
263+
// Without excluding `util` we get "TypeError: util.TextEncoder is not
264+
// a constructor" in react-server-dom-webpack.server because it'll try
265+
// to use Browserify's `util` instead of Node's. And Browserify's
266+
// polyfill is missing TextEncoder+TextDecoder. The reason it's using
267+
// the Browserify polyfill is because we have
268+
// `vite-plugin-node-polyfills` as a dependency, and that'll add
269+
// Browserify's `node-util` to `node_modules`, so when Vite goes to
270+
// resolve `import { TextEncoder } from 'util` it'll find the one in
271+
// `node_modules` instead of Node's internal version.
272+
// We only see this in dev, and not in prod. I'm not entirely sure why
273+
// but I have two guesses: 1. When RSC is enabled we don't actually use
274+
// `vite-plugin-node-polyfill`, so some kind of tree shaking is
275+
// happening, which prevents the issue from occurring. 2. In prod we
276+
// only use Node's dependency resolution. Vite is not involved. And
277+
// that difference in resolution is what prevents the issue from
278+
// occurring.
279+
exclude: ['util'],
262280
},
263281
},
264282
resolve: {
@@ -268,6 +286,10 @@ async function createServer() {
268286
{
269287
name: 'rsc-record-and-tranform-use-client-plugin',
270288
transform(code, id, _options) {
289+
// This is called from `getRoutesComponent()` in `clientSsr.ts`
290+
// during SSR. So options.ssr will be true in that case.
291+
// TODO (RSC): When is this called outside of SSR?
292+
271293
// TODO (RSC): We need to make sure this `id` always matches what
272294
// vite uses
273295
globalThis.__rwjs__client_references?.delete(id)
@@ -312,6 +334,7 @@ async function createServer() {
312334
return { code: result, map: null }
313335
},
314336
},
337+
rscTransformUseServerPlugin('', {}),
315338

316339
// The rscTransformUseClientPlugin maps paths like
317340
// /Users/tobbe/.../rw-app/node_modules/@tobbe.dev/rsc-test/dist/rsc-test.es.js
@@ -348,7 +371,8 @@ async function createServer() {
348371
// },
349372
},
350373
appType: 'custom',
351-
cacheDir: './node_modules/.vite-rsc',
374+
// Using a unique cache dir here to not clash with our other vite server
375+
cacheDir: '../node_modules/.vite-rsc',
352376
})
353377

354378
globalThis.__rwjs__vite_rsc_runtime = await createViteRuntime(viteRscServer)

packages/vite/src/plugins/vite-plugin-rsc-transform-server.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ export function rscTransformUseServerPlugin(
2121
return code
2222
}
2323

24+
if (
25+
id.includes('node_modules/.vite') ||
26+
id.includes('/react-server-dom-webpack/') ||
27+
id.includes('/react-server-dom-webpack.server')
28+
) {
29+
console.log('vite-plugin-rsc-transform-server.ts: Skipping', id)
30+
return code
31+
}
32+
2433
let mod: swc.Module
2534

2635
const isTypescript = id.endsWith('.ts') || id.endsWith('.tsx')

0 commit comments

Comments
 (0)