File tree Expand file tree Collapse file tree 6 files changed +102
-3
lines changed
examples/basic/src/framework Expand file tree Collapse file tree 6 files changed +102
-3
lines changed Original file line number Diff line number Diff line change @@ -453,6 +453,30 @@ This module re-exports RSC runtime API provided by `react-server-dom/server.edge
453453- ` decodeAction/decodeReply/decodeFormState/loadServerAction/createTemporaryReferenceSet `
454454- ` encodeReply/createClientTemporaryReferenceSet `
455455
456+ #### Vite-specific extension: ` renderToReadableStream ` (experimental)
457+
458+ > [ !NOTE]
459+ > This is a Vite-specific extension to the standard React RSC API. The official ` react-server-dom ` does not provide this callback mechanism.
460+
461+ ` renderToReadableStream ` API is extended with an optional third parameter with ` onClientReference ` callback.
462+ This is invoked whenever a client reference is used in RSC stream rendering.
463+
464+ ``` ts
465+ function renderToReadableStream<T >(
466+ data : T ,
467+ // standard options (e.g. temporaryReferences, onError, etc.)
468+ options ? : object ,
469+ // vite-specific options
470+ extraOptions ? : {
471+ onClientReference? : (metadata : {
472+ id: string
473+ name: string
474+ deps: { js: string []; css: string [] }
475+ }) => void
476+ },
477+ ): ReadableStream <Uint8Array >
478+ ```
479+
456480### ` @vitejs/plugin-rsc/ssr `
457481
458482This module re -exports RSC runtime API provided by ` react-server-dom/client.edge `
Original file line number Diff line number Diff line change @@ -237,6 +237,24 @@ function defineTest(f: Fixture) {
237237 expect ( f . proc ( ) . stderr ( ) ) . toBe ( '' )
238238 } )
239239
240+ test ( 'onClientReference callback' , async ( { page } ) => {
241+ const response = await page . request . get ( f . url ( '__test_onClientReference' ) )
242+ expect ( response . ok ( ) ) . toBe ( true )
243+ const data = await response . json ( )
244+ expect ( data ) . toEqual (
245+ expect . arrayContaining ( [
246+ expect . objectContaining ( {
247+ id : expect . any ( String ) ,
248+ name : expect . any ( String ) ,
249+ deps : expect . objectContaining ( {
250+ js : expect . any ( Array ) ,
251+ css : expect . any ( Array ) ,
252+ } ) ,
253+ } ) ,
254+ ] ) ,
255+ )
256+ } )
257+
240258 test ( 'client component' , async ( { page } ) => {
241259 await page . goto ( f . url ( ) )
242260 await waitForHydration ( page )
Original file line number Diff line number Diff line change @@ -79,7 +79,18 @@ async function handleRequest({
7979
8080 const rscPayload : RscPayload = { root : getRoot ( ) , formState, returnValue }
8181 const rscOptions = { temporaryReferences }
82- const rscStream = renderToReadableStream < RscPayload > ( rscPayload , rscOptions )
82+ const debugClientReferences : unknown [ ] = [ ]
83+ const rscStream = renderToReadableStream < RscPayload > ( rscPayload , rscOptions , {
84+ onClientReference ( metadata ) {
85+ debugClientReferences . push ( metadata )
86+ } ,
87+ } )
88+
89+ // test `onClientReference` callback
90+ if ( renderRequest . url . pathname === '/__test_onClientReference' ) {
91+ await rscStream . pipeTo ( new WritableStream ( { write ( ) { } } ) )
92+ return Response . json ( debugClientReferences )
93+ }
8394
8495 // Respond RSC stream without HTML rendering as decided by `RenderRequest`
8596 if ( renderRequest . isRsc ) {
Original file line number Diff line number Diff line change @@ -116,7 +116,12 @@ export function createServerDecodeClientManifest(): ModuleMap {
116116 )
117117}
118118
119- export function createClientManifest ( ) : BundlerConfig {
119+ export function createClientManifest ( options ?: {
120+ /**
121+ * @internal
122+ */
123+ onClientReference ?: ( metadata : { id : string ; name : string } ) => void
124+ } ) : BundlerConfig {
120125 const cacheTag = import . meta. env . DEV ? createReferenceCacheTag ( ) : ''
121126
122127 return new Proxy (
@@ -127,6 +132,7 @@ export function createClientManifest(): BundlerConfig {
127132 let [ id , name ] = $$id . split ( '#' )
128133 tinyassert ( id )
129134 tinyassert ( name )
135+ options ?. onClientReference ?.( { id, name } )
130136 return {
131137 id : id + cacheTag ,
132138 name,
Original file line number Diff line number Diff line change @@ -14,10 +14,18 @@ export { loadServerAction, setRequireModule } from '../core/rsc'
1414export function renderToReadableStream < T > (
1515 data : T ,
1616 options ?: object ,
17+ extraOptions ?: {
18+ /**
19+ * @internal
20+ */
21+ onClientReference ?: ( metadata : { id : string ; name : string } ) => void
22+ } ,
1723) : ReadableStream < Uint8Array > {
1824 return ReactServer . renderToReadableStream (
1925 data ,
20- createClientManifest ( ) ,
26+ createClientManifest ( {
27+ onClientReference : extraOptions ?. onClientReference ,
28+ } ) ,
2129 options ,
2230 )
2331}
Original file line number Diff line number Diff line change 1+ import assetsManifest from 'virtual:vite-rsc/assets-manifest'
12import serverReferences from 'virtual:vite-rsc/server-references'
23import { setRequireModule } from './core/rsc'
4+ import type { ResolvedAssetDeps } from './plugin'
35import { toReferenceValidationVirtual } from './plugins/shared'
6+ import { renderToReadableStream as originalRenderToReadableStream } from './react/rsc'
47
58export {
69 createClientManifest ,
@@ -36,3 +39,32 @@ function initialize(): void {
3639 } ,
3740 } )
3841}
42+
43+ export function renderToReadableStream < T > (
44+ data : T ,
45+ options ?: object ,
46+ extraOptions ?: {
47+ /**
48+ * @experimental
49+ */
50+ onClientReference ?: ( metadata : {
51+ id : string
52+ name : string
53+ deps : ResolvedAssetDeps
54+ } ) => void
55+ } ,
56+ ) : ReadableStream < Uint8Array > {
57+ return originalRenderToReadableStream ( data , options , {
58+ onClientReference ( metadata ) {
59+ const deps = assetsManifest . clientReferenceDeps [ metadata . id ] ?? {
60+ js : [ ] ,
61+ css : [ ] ,
62+ }
63+ extraOptions ?. onClientReference ?.( {
64+ id : metadata . id ,
65+ name : metadata . name ,
66+ deps,
67+ } )
68+ } ,
69+ } )
70+ }
You can’t perform that action at this time.
0 commit comments