Skip to content

Commit 1d91f40

Browse files
committed
feat(rsc): configure server reference markers
1 parent 715864b commit 1d91f40

2 files changed

Lines changed: 59 additions & 2 deletions

File tree

packages/plugin-rsc/src/plugin.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,48 @@ describe('server reference manifest', () => {
5353
expect(manifest.code.match(/\bcached\b/g)).toHaveLength(2)
5454
expect(manifest.code.match(/\baction\b/g)).toHaveLength(2)
5555
})
56+
57+
it('preserves metadata for configured server reference markers', async () => {
58+
const marker = '/* framework-server-reference */'
59+
const plugins = vitePluginRscMinimal({
60+
enableActionEncryption: false,
61+
serverReferenceMarkers: [marker, ''],
62+
})
63+
const minimalPlugin = plugins.find(
64+
(plugin) => plugin.name === 'rsc:minimal',
65+
)!
66+
const manager = (minimalPlugin.api as any).manager
67+
const useServerPlugin = plugins.find(
68+
(plugin) => plugin.name === 'rsc:use-server',
69+
)!
70+
const transformHandler = (useServerPlugin.transform as any).handler
71+
const transformContext = {
72+
environment: { name: 'rsc', mode: 'build' },
73+
error(error: unknown) {
74+
throw error
75+
},
76+
}
77+
78+
const markedId = '/root/marked.ts'
79+
manager.serverReferenceMetaMap[markedId] = {
80+
importId: markedId,
81+
referenceKey: 'marked',
82+
exportNames: ['cached'],
83+
}
84+
await transformHandler.call(
85+
transformContext,
86+
`${marker}\nexport {}`,
87+
markedId,
88+
)
89+
expect(manager.serverReferenceMetaMap[markedId]).toBeDefined()
90+
91+
const unmarkedId = '/root/unmarked.ts'
92+
manager.serverReferenceMetaMap[unmarkedId] = {
93+
importId: unmarkedId,
94+
referenceKey: 'unmarked',
95+
exportNames: ['stale'],
96+
}
97+
await transformHandler.call(transformContext, 'export {}', unmarkedId)
98+
expect(manager.serverReferenceMetaMap[unmarkedId]).toBeUndefined()
99+
})
56100
})

packages/plugin-rsc/src/plugin.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,13 @@ class RscPluginManager {
171171
}
172172

173173
export type RscPluginOptions = {
174+
/**
175+
* Source markers emitted by preceding transforms that register server
176+
* references in the plugin manager. Modules containing a marker keep their
177+
* existing server-reference metadata when they do not contain `"use server"`.
178+
* @experimental
179+
*/
180+
serverReferenceMarkers?: string[]
174181
/**
175182
* shorthand for configuring `environments.(name).build.rollupOptions.input.index`
176183
*/
@@ -1926,7 +1933,7 @@ function vitePluginDefineEncryptionKey(
19261933
function vitePluginUseServer(
19271934
useServerPluginOptions: Pick<
19281935
RscPluginOptions,
1929-
'enableActionEncryption' | 'environment'
1936+
'enableActionEncryption' | 'environment' | 'serverReferenceMarkers'
19301937
>,
19311938
manager: RscPluginManager,
19321939
): Plugin[] {
@@ -1946,7 +1953,13 @@ function vitePluginUseServer(
19461953
// filter: { code: 'use server' },
19471954
async handler(code, id) {
19481955
if (!code.includes('use server')) {
1949-
delete manager.serverReferenceMetaMap[id]
1956+
const hasServerReferenceMarker =
1957+
useServerPluginOptions.serverReferenceMarkers?.some(
1958+
(marker) => marker.length > 0 && code.includes(marker),
1959+
) ?? false
1960+
if (!hasServerReferenceMarker) {
1961+
delete manager.serverReferenceMetaMap[id]
1962+
}
19501963
return
19511964
}
19521965
let ast = await parseAstAsync(code)

0 commit comments

Comments
 (0)