diff --git a/packages/plugin-rsc/README.md b/packages/plugin-rsc/README.md index 23fda67ce..b271ab298 100644 --- a/packages/plugin-rsc/README.md +++ b/packages/plugin-rsc/README.md @@ -186,20 +186,19 @@ if (import.meta.hot) { - [`entry.ssr.tsx`](./examples/starter/src/framework/entry.ssr.tsx) ```tsx -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import { renderToReadableStream } from 'react-dom/server.edge' export async function handleSsr(rscStream: ReadableStream) { // deserialize RSC stream back to React VDOM const root = await createFromReadableStream(rscStream) - // helper API to allow referencing browser entry content from SSR environment - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') - // render html (traditional SSR) const htmlStream = renderToReadableStream(root, { - bootstrapScriptContent, + bootstrapModules: [getClientEntryUrl()], }) return htmlStream @@ -334,20 +333,21 @@ export function UserApp() { ### Available on `ssr` environment -#### `import.meta.viteRsc.loadBootstrapScriptContent("index")` +#### `getClientEntryUrl()` -This provides a raw js code to execute a browser entry file specified by `environments.client.build.rollupOptions.input.index`. This is intended to be used with React DOM SSR API, such as [`renderToReadableStream`](https://react.dev/reference/react-dom/server/renderToReadableStream) +This returns the URL used to load the client entry specified by `environments.client.build.rollupOptions.input.index`. This can be used with React DOM SSR APIs such as [`renderToReadableStream`](https://react.dev/reference/react-dom/server/renderToReadableStream). ```js +import { getClientEntryUrl } from '@vitejs/plugin-rsc/ssr' import { renderToReadableStream } from 'react-dom/server.edge' -const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') const htmlStream = await renderToReadableStream(reactNode, { - bootstrapScriptContent, + bootstrapModules: [getClientEntryUrl()], }) ``` +`getClientEntryUrl()` cannot be used when the `customClientEntry` plugin option is enabled. + ### Available on `client` environment #### `rsc:update` event diff --git a/packages/plugin-rsc/e2e/client-entry-url.test.ts b/packages/plugin-rsc/e2e/client-entry-url.test.ts new file mode 100644 index 000000000..54e27f9d9 --- /dev/null +++ b/packages/plugin-rsc/e2e/client-entry-url.test.ts @@ -0,0 +1,90 @@ +import { expect, test } from '@playwright/test' +import { setupInlineFixture, useFixture } from './fixture' + +test.describe('getClientEntryUrl', () => { + const root = 'examples/e2e/temp/client-entry-url' + + test.beforeAll(async () => { + await setupInlineFixture({ + src: 'examples/starter-extra', + dest: root, + files: { + 'src/framework/entry.ssr.tsx': /* tsx */ ` + import { getClientEntryUrl } from '@vitejs/plugin-rsc/ssr' + + export async function renderHTML() { + const clientEntryUrl = getClientEntryUrl() + const legacyBootstrapScriptContent = + await import.meta.viteRsc.loadBootstrapScriptContent('index') + const content = JSON.stringify({ + clientEntryUrl, + legacyBootstrapScriptContent, + }) + return { stream: new Response(content).body! } + } + `, + }, + }) + }) + + function defineTest(mode: 'dev' | 'build') { + const f = useFixture({ root, mode }) + + test('returns the client entry URL', async ({ request }) => { + const response = await request.get(f.url()) + const result = await response.json() + expect(result.legacyBootstrapScriptContent).toBe( + `import(${JSON.stringify(result.clientEntryUrl)})`, + ) + if (mode === 'dev') { + expect(result.clientEntryUrl).toContain( + '/@id/__x00__virtual:vite-rsc/entry-browser', + ) + } else { + expect(result.clientEntryUrl).toMatch(/\/assets\/index-[\w-]+\.js$/) + } + }) + } + + test.describe('dev', () => defineTest('dev')) + test.describe('build', () => defineTest('build')) +}) + +test.describe('getClientEntryUrl with customClientEntry', () => { + const root = 'examples/e2e/temp/client-entry-url-custom' + + test.beforeAll(async () => { + await setupInlineFixture({ + src: 'examples/starter-extra', + dest: root, + files: { + 'vite.config.ts': { + edit: (source) => + source.replace('rsc()', 'rsc({ customClientEntry: true })'), + }, + 'src/framework/entry.ssr.tsx': /* tsx */ ` + import { getClientEntryUrl } from '@vitejs/plugin-rsc/ssr' + + export async function renderHTML() { + let content = 'unexpected success' + try { + getClientEntryUrl() + } catch (error) { + content = String(error) + } + return { stream: new Response(content).body! } + } + `, + }, + }) + }) + + const f = useFixture({ root, mode: 'build' }) + + test('throws with customClientEntry', async ({ request }) => { + const response = await request.get(f.url()) + await expect(response.text()).resolves.toContain( + `[vite-rsc] getClientEntryUrl() cannot be used with the 'customClientEntry' option`, + ) + }) +}) diff --git a/packages/plugin-rsc/e2e/render-built-url.test.ts b/packages/plugin-rsc/e2e/render-built-url.test.ts index 9f51ecc1d..6c9dec9d9 100644 --- a/packages/plugin-rsc/e2e/render-built-url.test.ts +++ b/packages/plugin-rsc/e2e/render-built-url.test.ts @@ -111,6 +111,9 @@ test.describe(() => { expect(manifestFileContent).toContain( `__dynamicBase + "assets/entry.rsc-`, ) + expect(manifestFileContent).toMatch( + /"clientEntryUrl": __dynamicBase \+ "assets\/index-[\w-]+\.js"/, + ) }) }) }) diff --git a/packages/plugin-rsc/examples/action-reachability/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/action-reachability/src/framework/entry.ssr.tsx index 6eb6b3650..65b4dbd56 100644 --- a/packages/plugin-rsc/examples/action-reachability/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/action-reachability/src/framework/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import React from 'react' import type { ReactFormState } from 'react-dom/client' import { renderToReadableStream } from 'react-dom/server.edge' @@ -21,8 +24,7 @@ export async function renderHTML( return React.use(payload).root } - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` let htmlStream: ReadableStream let status: number | undefined try { diff --git a/packages/plugin-rsc/examples/basic/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/basic/src/framework/entry.ssr.tsx index 9e2e6db27..7f754a457 100644 --- a/packages/plugin-rsc/examples/basic/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/basic/src/framework/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import React from 'react' import type { ReactFormState } from 'react-dom/client' import { renderToReadableStream } from 'react-dom/server.edge' @@ -21,8 +24,7 @@ export async function renderHTML( return React.use(payload).root } - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` let htmlStream: ReadableStream let status: number | undefined try { diff --git a/packages/plugin-rsc/examples/cache-replay/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/cache-replay/src/framework/entry.ssr.tsx index d28ef5e5a..4d0b655a6 100644 --- a/packages/plugin-rsc/examples/cache-replay/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/cache-replay/src/framework/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import React from 'react' import type { ReactFormState } from 'react-dom/client' import { renderToReadableStream } from 'react-dom/server.edge' @@ -21,8 +24,7 @@ export async function renderHTML( return React.use(payload).root } - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` let htmlStream: ReadableStream let status: number | undefined try { diff --git a/packages/plugin-rsc/examples/client-first/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/client-first/src/framework/entry.ssr.tsx index e0b536e32..20cccb34d 100644 --- a/packages/plugin-rsc/examples/client-first/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/client-first/src/framework/entry.ssr.tsx @@ -1,11 +1,13 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import { renderToReadableStream } from 'react-dom/server.edge' import { Root } from '../root' import { setRscFnCaller, type RscFnCaller } from './runtime' export async function renderHtml() { - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` return renderToReadableStream(, { bootstrapScriptContent }) } diff --git a/packages/plugin-rsc/examples/custom-server-function/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/custom-server-function/src/framework/entry.ssr.tsx index 6eb6b3650..65b4dbd56 100644 --- a/packages/plugin-rsc/examples/custom-server-function/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/custom-server-function/src/framework/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import React from 'react' import type { ReactFormState } from 'react-dom/client' import { renderToReadableStream } from 'react-dom/server.edge' @@ -21,8 +24,7 @@ export async function renderHTML( return React.use(payload).root } - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` let htmlStream: ReadableStream let status: number | undefined try { diff --git a/packages/plugin-rsc/examples/performance-track/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/performance-track/src/framework/entry.ssr.tsx index 060be0438..2097f10bc 100644 --- a/packages/plugin-rsc/examples/performance-track/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/performance-track/src/framework/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import React from 'react' import { renderToReadableStream } from 'react-dom/server.edge' import { injectRSCPayload } from 'rsc-html-stream/server' @@ -15,8 +18,7 @@ export async function renderHTML( return React.use(payload).root } - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` const htmlStream = await renderToReadableStream(, { bootstrapScriptContent, }) diff --git a/packages/plugin-rsc/examples/ppr/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/ppr/src/framework/entry.ssr.tsx index ecd1aa10e..c32b692a3 100644 --- a/packages/plugin-rsc/examples/ppr/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/ppr/src/framework/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import React from 'react' import { resume } from 'react-dom/server.edge' import type { PrerenderResult } from 'react-dom/static' @@ -11,8 +14,7 @@ export async function prerenderHtml( rscStream: ReadableStream, ): Promise { const ssrRoot = createSsrRoot(preventStreamClose(rscStream)) - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` const controller = new AbortController() const pendingResult = prerender(ssrRoot, { bootstrapScriptContent, diff --git a/packages/plugin-rsc/examples/react-router/react-router-vite/entry.ssr.tsx b/packages/plugin-rsc/examples/react-router/react-router-vite/entry.ssr.tsx index 4e356c1b3..34663da29 100644 --- a/packages/plugin-rsc/examples/react-router/react-router-vite/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/react-router/react-router-vite/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import { renderToReadableStream as renderHTMLToReadableStream } from 'react-dom/server.edge' import { unstable_routeRSCServerRequest as routeRSCServerRequest, @@ -9,8 +12,7 @@ export default async function handler( request: Request, serverResponse: Response, ): Promise { - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` return await routeRSCServerRequest({ request, diff --git a/packages/plugin-rsc/examples/ssg/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/ssg/src/framework/entry.ssr.tsx index 04995bb35..95ddf8629 100644 --- a/packages/plugin-rsc/examples/ssg/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/ssg/src/framework/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import React from 'react' import { renderToReadableStream } from 'react-dom/server.edge' import { prerender } from 'react-dom/static.edge' @@ -19,8 +22,7 @@ export async function renderHtml( const root = React.use(payload).root return root } - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` let htmlStream: ReadableStream let status: number | undefined diff --git a/packages/plugin-rsc/examples/starter-extra/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/starter-extra/src/framework/entry.ssr.tsx index 6eb6b3650..65b4dbd56 100644 --- a/packages/plugin-rsc/examples/starter-extra/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/starter-extra/src/framework/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import React from 'react' import type { ReactFormState } from 'react-dom/client' import { renderToReadableStream } from 'react-dom/server.edge' @@ -21,8 +24,7 @@ export async function renderHTML( return React.use(payload).root } - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` let htmlStream: ReadableStream let status: number | undefined try { diff --git a/packages/plugin-rsc/examples/starter/README.md b/packages/plugin-rsc/examples/starter/README.md index 95f948a00..7fcb4af00 100644 --- a/packages/plugin-rsc/examples/starter/README.md +++ b/packages/plugin-rsc/examples/starter/README.md @@ -24,7 +24,7 @@ See [`@vitejs/plugin-rsc`](https://github.com/vitejs/vite-plugin-react/tree/main - `import.meta.viteRsc.loadModule` - [`./src/framework/entry.ssr.tsx`](./src/framework/entry.ssr.tsx) - `@vitejs/plugin-rsc/ssr` - - `import.meta.viteRsc.loadBootstrapScriptContent` + - `getClientEntryUrl` - `rsc-html-stream/server` - [`./src/framework/entry.browser.tsx`](./src/framework/entry.browser.tsx) - `@vitejs/plugin-rsc/browser` diff --git a/packages/plugin-rsc/examples/starter/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/starter/src/framework/entry.ssr.tsx index 7fc5a9564..1817137d3 100644 --- a/packages/plugin-rsc/examples/starter/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/starter/src/framework/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import React from 'react' import type { ReactFormState } from 'react-dom/client' import { renderToReadableStream } from 'react-dom/server.edge' @@ -28,8 +31,7 @@ export async function renderHTML( } // render html (traditional SSR) - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` let htmlStream: ReadableStream let status: number | undefined try { diff --git a/packages/plugin-rsc/examples/use-cache-callable/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/use-cache-callable/src/framework/entry.ssr.tsx index 6eb6b3650..65b4dbd56 100644 --- a/packages/plugin-rsc/examples/use-cache-callable/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/use-cache-callable/src/framework/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import React from 'react' import type { ReactFormState } from 'react-dom/client' import { renderToReadableStream } from 'react-dom/server.edge' @@ -21,8 +24,7 @@ export async function renderHTML( return React.use(payload).root } - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` let htmlStream: ReadableStream let status: number | undefined try { diff --git a/packages/plugin-rsc/examples/use-cache/src/framework/entry.ssr.tsx b/packages/plugin-rsc/examples/use-cache/src/framework/entry.ssr.tsx index 6eb6b3650..65b4dbd56 100644 --- a/packages/plugin-rsc/examples/use-cache/src/framework/entry.ssr.tsx +++ b/packages/plugin-rsc/examples/use-cache/src/framework/entry.ssr.tsx @@ -1,4 +1,7 @@ -import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr' +import { + createFromReadableStream, + getClientEntryUrl, +} from '@vitejs/plugin-rsc/ssr' import React from 'react' import type { ReactFormState } from 'react-dom/client' import { renderToReadableStream } from 'react-dom/server.edge' @@ -21,8 +24,7 @@ export async function renderHTML( return React.use(payload).root } - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') + const bootstrapScriptContent = `import(${JSON.stringify(getClientEntryUrl())})` let htmlStream: ReadableStream let status: number | undefined try { diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index 965e7eaaf..b29404cbc 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -284,7 +284,8 @@ export type RscPluginOptions = { * - Require an entry chunk named "index" * - Automatically include client entry deps in each client reference's dependencies * - * Note: `import.meta.viteRsc.loadBootstrapScriptContent` cannot be used with this option. + * Note: `getClientEntryUrl` and `import.meta.viteRsc.loadBootstrapScriptContent` + * cannot be used with this option. * * Use this when you manually handle client entry setup and preloading. * @@ -1129,7 +1130,9 @@ export function createRpcClient(params) { manager, ) const manifest: AssetsManifest = { - bootstrapScriptContent: `import(${serializeValueWithRuntime(entryUrl)})`, + clientEntryUrl: rscPluginOptions.customClientEntry + ? undefined + : entryUrl, clientReferenceDeps: {}, cssLinkPrecedence: rscPluginOptions.cssLinkPrecedence, } @@ -1200,7 +1203,7 @@ export function createRpcClient(params) { } const assetDeps = collectAssetDeps(bundle) - let bootstrapScriptContent: string | RuntimeAsset = '' + let clientEntryUrl: string | RuntimeAsset | undefined let clientEntryDeps: AssetDeps | undefined const clientReferenceDeps: Record = {} @@ -1230,18 +1233,11 @@ export function createRpcClient(params) { for (const [key, deps] of Object.entries(clientReferenceDeps)) { clientReferenceDeps[key] = mergeAssetDeps(deps, clientEntryDeps) } - const entryUrl = assetsURL(entry.chunk.fileName, manager) - if (typeof entryUrl === 'string') { - bootstrapScriptContent = `import(${JSON.stringify(entryUrl)})` - } else { - bootstrapScriptContent = new RuntimeAsset( - `"import(" + JSON.stringify(${entryUrl.runtime}) + ")"`, - ) - } + clientEntryUrl = assetsURL(entry.chunk.fileName, manager) } manager.buildAssetsManifest = { - bootstrapScriptContent, + clientEntryUrl, clientEntryDeps, clientReferenceDeps, serverResources, @@ -1268,13 +1264,6 @@ export function createRpcClient(params) { return }, }, - createVirtualPlugin('vite-rsc/bootstrap-script-content', function () { - assert(this.environment.name !== 'client') - return `\ -import assetsManifest from "virtual:vite-rsc/assets-manifest"; -export default assetsManifest.bootstrapScriptContent; -` - }), { name: 'rsc:bootstrap-script-content', transform: { @@ -1306,7 +1295,7 @@ export default assetsManifest.bootstrapScriptContent; entryName, `[vite-rsc] expected 'loadBootstrapScriptContent("index")' but got ${argCode}`, ) - let replacement: string = `Promise.resolve(__vite_rsc_assets_manifest.bootstrapScriptContent)` + let replacement: string = `Promise.resolve("import(" + JSON.stringify(__vite_rsc_assets_manifest.clientEntryUrl) + ")")` const [start, end] = match.indices![0]! output.overwrite(start, end, replacement) } @@ -2265,7 +2254,7 @@ function assetsURLOfDeps(deps: AssetDeps, manager: RscPluginManager) { // export type AssetsManifest = { - bootstrapScriptContent: string | RuntimeAsset + clientEntryUrl?: string | RuntimeAsset clientEntryDeps?: AssetDeps clientReferenceDeps: Record serverResources?: Record> @@ -2278,7 +2267,7 @@ export type AssetDeps = { } export type ResolvedAssetsManifest = { - bootstrapScriptContent: string + clientEntryUrl?: string clientEntryDeps?: ResolvedAssetDeps clientReferenceDeps: Record serverResources?: Record> diff --git a/packages/plugin-rsc/src/ssr.tsx b/packages/plugin-rsc/src/ssr.tsx index 002cf2092..581a0d66c 100644 --- a/packages/plugin-rsc/src/ssr.tsx +++ b/packages/plugin-rsc/src/ssr.tsx @@ -9,6 +9,16 @@ export { createServerConsumerManifest } from './core/ssr' export * from './react/ssr' +export function getClientEntryUrl(): string { + const url = assetsManifest.clientEntryUrl + if (!url) { + throw new Error( + `[vite-rsc] getClientEntryUrl() cannot be used with the 'customClientEntry' option`, + ) + } + return url +} + /** * Callback type for client reference dependency notifications. * Called during SSR when a client component's dependencies are loaded. diff --git a/packages/plugin-rsc/types/index.d.ts b/packages/plugin-rsc/types/index.d.ts index 5eafb4ee1..ee4116c07 100644 --- a/packages/plugin-rsc/types/index.d.ts +++ b/packages/plugin-rsc/types/index.d.ts @@ -3,6 +3,7 @@ declare global { readonly viteRsc: { loadCss: (importer?: string) => import('react').ReactNode loadModule: (environmentName: string, entryName?: string) => Promise + /** @deprecated Use `getClientEntryUrl` from `@vitejs/plugin-rsc/ssr`. */ loadBootstrapScriptContent: (entryName: string) => Promise /** * Import a module from another environment using a module specifier.