diff --git a/packages/plugin-rsc/examples/basic/src/framework/entry.rsc.tsx b/packages/plugin-rsc/examples/basic/src/framework/entry.rsc.tsx index f3fff1842..b98c4433f 100644 --- a/packages/plugin-rsc/examples/basic/src/framework/entry.rsc.tsx +++ b/packages/plugin-rsc/examples/basic/src/framework/entry.rsc.tsx @@ -85,7 +85,7 @@ export async function handleRequest({ } // Delegate to SSR environment for html rendering. - // The plugin provides `loadSsrModule` helper to allow loading SSR environment entry module + // The plugin provides `loadModule` helper to allow loading SSR environment entry module // in RSC environment. however this can be customized by implementing own runtime communication // e.g. `@cloudflare/vite-plugin`'s service binding. const ssrEntryModule = await import.meta.viteRsc.loadModule< diff --git a/packages/plugin-rsc/examples/e2e/package.json b/packages/plugin-rsc/examples/e2e/package.json index 9121f0090..0274499a3 100644 --- a/packages/plugin-rsc/examples/e2e/package.json +++ b/packages/plugin-rsc/examples/e2e/package.json @@ -7,6 +7,7 @@ "@vitejs/plugin-rsc": "latest", "babel-plugin-react-compiler": "19.1.0-rc.3", "connect": "^3.7.0", + "rsc-html-stream": "^0.0.7", "sirv": "^3.0.2" } } diff --git a/packages/plugin-rsc/examples/starter/src/framework/entry.rsc.tsx b/packages/plugin-rsc/examples/starter/src/framework/entry.rsc.tsx index fa1c27845..ab5a55a24 100644 --- a/packages/plugin-rsc/examples/starter/src/framework/entry.rsc.tsx +++ b/packages/plugin-rsc/examples/starter/src/framework/entry.rsc.tsx @@ -85,7 +85,7 @@ export default async function handler(request: Request): Promise { } // Delegate to SSR environment for html rendering. - // The plugin provides `loadSsrModule` helper to allow loading SSR environment entry module + // The plugin provides `loadModule` helper to allow loading SSR environment entry module // in RSC environment. however this can be customized by implementing own runtime communication // e.g. `@cloudflare/vite-plugin`'s service binding. const ssrEntryModule = await import.meta.viteRsc.loadModule< diff --git a/packages/plugin-rsc/package.json b/packages/plugin-rsc/package.json index 8fe6c56c2..74210f460 100644 --- a/packages/plugin-rsc/package.json +++ b/packages/plugin-rsc/package.json @@ -60,7 +60,6 @@ "react": "^19.1.1", "react-dom": "^19.1.1", "react-server-dom-webpack": "^19.1.1", - "rsc-html-stream": "^0.0.7", "tinyexec": "^1.0.1", "tsdown": "^0.15.6" }, diff --git a/packages/plugin-rsc/src/extra/browser.tsx b/packages/plugin-rsc/src/extra/browser.tsx deleted file mode 100644 index 4bf272e9a..000000000 --- a/packages/plugin-rsc/src/extra/browser.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import React from 'react' -import ReactDomClient from 'react-dom/client' -import { rscStream } from 'rsc-html-stream/client' -import { - type CallServerCallback, - createFromFetch, - createFromReadableStream, - createTemporaryReferenceSet, - encodeReply, - setServerCallback, -} from '../browser' -import type { RscPayload } from './rsc' - -/** - * @deprecated Use `@vitejs/plugin-rsc/browser` API instead. - */ -export async function hydrate(): Promise { - const callServer: CallServerCallback = async (id, args) => { - const url = new URL(window.location.href) - const temporaryReferences = createTemporaryReferenceSet() - const payload = await createFromFetch( - fetch(url, { - method: 'POST', - body: await encodeReply(args, { temporaryReferences }), - headers: { - 'x-rsc-action': id, - }, - }), - { temporaryReferences }, - ) - setPayload(payload) - return payload.returnValue - } - setServerCallback(callServer) - - async function onNavigation() { - const url = new URL(window.location.href) - const payload = await createFromFetch(fetch(url)) - setPayload(payload) - } - - const initialPayload = await createFromReadableStream(rscStream) - - let setPayload: (v: RscPayload) => void - - function BrowserRoot() { - const [payload, setPayload_] = React.useState(initialPayload) - - React.useEffect(() => { - setPayload = (v) => React.startTransition(() => setPayload_(v)) - }, [setPayload_]) - - React.useEffect(() => { - return listenNavigation(() => onNavigation()) - }, []) - - return payload.root - } - - const browserRoot = ( - - - - ) - - ReactDomClient.hydrateRoot(document, browserRoot, { - formState: initialPayload.formState, - }) - - if (import.meta.hot) { - import.meta.hot.on('rsc:update', () => { - window.history.replaceState({}, '', window.location.href) - }) - } -} - -/** - * @deprecated Use `@vitejs/plugin-rsc/browser` API instead. - */ -export async function fetchRSC( - request: string | URL | Request, -): Promise { - const payload = await createFromFetch(fetch(request)) - return payload.root -} - -function listenNavigation(onNavigation: () => void): () => void { - window.addEventListener('popstate', onNavigation) - - const oldPushState = window.history.pushState - window.history.pushState = function (...args) { - const res = oldPushState.apply(this, args) - onNavigation() - return res - } - - const oldReplaceState = window.history.replaceState - window.history.replaceState = function (...args) { - const res = oldReplaceState.apply(this, args) - onNavigation() - return res - } - - function onClick(e: MouseEvent) { - let link = (e.target as Element).closest('a') - if ( - link && - link instanceof HTMLAnchorElement && - link.href && - (!link.target || link.target === '_self') && - link.origin === location.origin && - !link.hasAttribute('download') && - e.button === 0 && // left clicks only - !e.metaKey && // open in new tab (mac) - !e.ctrlKey && // open in new tab (windows) - !e.altKey && // download - !e.shiftKey && - !e.defaultPrevented - ) { - e.preventDefault() - history.pushState(null, '', link.href) - } - } - document.addEventListener('click', onClick) - - return () => { - document.removeEventListener('click', onClick) - window.removeEventListener('popstate', onNavigation) - window.history.pushState = oldPushState - window.history.replaceState = oldReplaceState - } -} diff --git a/packages/plugin-rsc/src/extra/rsc.tsx b/packages/plugin-rsc/src/extra/rsc.tsx deleted file mode 100644 index 393dae1dd..000000000 --- a/packages/plugin-rsc/src/extra/rsc.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import type { ReactFormState } from 'react-dom/client' -import { - createTemporaryReferenceSet, - decodeAction, - decodeFormState, - decodeReply, - loadServerAction, - renderToReadableStream, -} from '../rsc' - -export type RscPayload = { - root: React.ReactNode - formState?: ReactFormState - returnValue?: unknown -} - -/** - * @deprecated Use `@vitejs/plugin-rsc/rsc` API instead. - */ -export async function renderRequest( - request: Request, - root: React.ReactNode, - options?: { nonce?: string }, -): Promise { - function RscRoot() { - // https://vite.dev/guide/features.html#content-security-policy-csp - // this isn't needed if `style-src: 'unsafe-inline'` (dev) and `script-src: 'self'` - const nonceMeta = options?.nonce && ( - - ) - return ( - <> - {nonceMeta} - {root} - - ) - } - - const url = new URL(request.url) - const isAction = request.method === 'POST' - - // use ?__rsc and ?__html for quick debugging - const isRscRequest = - (!request.headers.get('accept')?.includes('text/html') && - !url.searchParams.has('__html')) || - url.searchParams.has('__rsc') - - // TODO: error handling - // callAction - let returnValue: unknown | undefined - let formState: ReactFormState | undefined - let temporaryReferences: unknown | undefined - if (isAction) { - const actionId = request.headers.get('x-rsc-action') - if (actionId) { - // client stream request - const contentType = request.headers.get('content-type') - const body = contentType?.startsWith('multipart/form-data') - ? await request.formData() - : await request.text() - temporaryReferences = createTemporaryReferenceSet() - const args = await decodeReply(body, { temporaryReferences }) - const action = await loadServerAction(actionId) - returnValue = await action.apply(null, args) - } else { - // progressive enhancement - const formData = await request.formData() - const decodedAction = await decodeAction(formData) - const result = await decodedAction() - formState = await decodeFormState(result, formData) - } - } - - const rscPayload: RscPayload = { root: , formState, returnValue } - const rscOptions = { temporaryReferences } - const rscStream = renderToReadableStream(rscPayload, rscOptions) - - if (isRscRequest) { - return new Response(rscStream, { - headers: { - 'content-type': 'text/x-component;charset=utf-8', - vary: 'accept', - }, - }) - } - - const ssrEntry = await import.meta.viteRsc.loadModule( - 'ssr', - 'index', - ) - return ssrEntry.renderHtml(rscStream, { - formState, - nonce: options?.nonce, - debugNoJs: url.searchParams.has('__nojs'), - }) -} diff --git a/packages/plugin-rsc/src/extra/ssr.tsx b/packages/plugin-rsc/src/extra/ssr.tsx deleted file mode 100644 index 6e8c71bb2..000000000 --- a/packages/plugin-rsc/src/extra/ssr.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react' -import type { ReactFormState } from 'react-dom/client' -import ReactDomServer from 'react-dom/server.edge' -import { injectRSCPayload } from 'rsc-html-stream/server' -import { createFromReadableStream } from '../ssr' -import type { RscPayload } from './rsc' - -/** - * @deprecated Use `@vitejs/plugin-rsc/ssr` API instead. - */ -export async function renderHtml( - rscStream: ReadableStream, - options?: { - formState?: ReactFormState - nonce?: string - debugNoJs?: boolean - }, -): Promise { - const [rscStream1, rscStream2] = rscStream.tee() - - // flight deserialization needs to be kicked off inside SSR context - // for ReactDomServer preinit/preloading to work - let payload: Promise - function SsrRoot() { - payload ??= createFromReadableStream(rscStream1, { - nonce: options?.nonce, - }) - const root = React.use(payload).root - return root - } - - const bootstrapScriptContent = - await import.meta.viteRsc.loadBootstrapScriptContent('index') - const htmlStream = await ReactDomServer.renderToReadableStream(, { - bootstrapScriptContent: options?.debugNoJs - ? undefined - : bootstrapScriptContent, - nonce: options?.nonce, - formState: options?.formState, - }) - - let responseStream: ReadableStream = htmlStream - if (!options?.debugNoJs) { - responseStream = responseStream.pipeThrough( - injectRSCPayload(rscStream2, { - nonce: options?.nonce, - }), - ) - } - - return new Response(responseStream, { - headers: { - 'content-type': 'text/html;charset=utf-8', - vary: 'accept', - }, - }) -} diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index 2d7605de3..1dd69d51a 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -124,9 +124,6 @@ export type RscPluginOptions = { */ entries?: Partial> - /** @deprecated use `serverHandler: false` */ - disableServerHandler?: boolean - /** @default { enviornmentName: "rsc", entryName: "index" } */ serverHandler?: | { @@ -140,9 +137,6 @@ export type RscPluginOptions = { rscCssTransform?: false | { filter?: (id: string) => boolean } - /** @deprecated use "DEBUG=vite-env:*" to see warnings. */ - ignoredPackageWarnings?: (string | RegExp)[] - /** * This option allows customizing how client build copies assets from server build. * By default, all assets are copied, but frameworks can establish server asset convention @@ -502,7 +496,6 @@ export default function vitePluginRsc( return oldSend.apply(this, args as any) } - if (rscPluginOptions.disableServerHandler) return if (rscPluginOptions.serverHandler === false) return const options = rscPluginOptions.serverHandler ?? { environmentName: 'rsc', @@ -539,7 +532,6 @@ export default function vitePluginRsc( } }, async configurePreviewServer(server) { - if (rscPluginOptions.disableServerHandler) return if (rscPluginOptions.serverHandler === false) return const options = rscPluginOptions.serverHandler ?? { environmentName: 'rsc', @@ -701,18 +693,6 @@ export default function vitePluginRsc( }, }, }, - { - // backward compat: `loadSsrModule(name)` implemented as `loadModule("ssr", name)` - name: 'rsc:load-ssr-module', - transform(code) { - if (code.includes('import.meta.viteRsc.loadSsrModule(')) { - return code.replaceAll( - `import.meta.viteRsc.loadSsrModule(`, - `import.meta.viteRsc.loadModule("ssr", `, - ) - } - }, - }, { // allow loading entry module in other environment by // - (dev) rewriting to `server.environments[].runner.import()` diff --git a/packages/plugin-rsc/src/rsc-html-stream/browser.ts b/packages/plugin-rsc/src/rsc-html-stream/browser.ts deleted file mode 100644 index 166faf332..000000000 --- a/packages/plugin-rsc/src/rsc-html-stream/browser.ts +++ /dev/null @@ -1,5 +0,0 @@ -import * as rscHtmlStreamClient from 'rsc-html-stream/client' - -/** @deprecated use `rsc-html-stream/client` instead */ -export const getRscStreamFromHtml = (): ReadableStream => - rscHtmlStreamClient.rscStream diff --git a/packages/plugin-rsc/src/rsc-html-stream/ssr.ts b/packages/plugin-rsc/src/rsc-html-stream/ssr.ts deleted file mode 100644 index 92c0b57d1..000000000 --- a/packages/plugin-rsc/src/rsc-html-stream/ssr.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as rscHtmlStreamServer from 'rsc-html-stream/server' - -/** @deprecated use `rsc-html-stream/server` instead */ -export const injectRscStreamToHtml = ( - stream: ReadableStream, - options?: { nonce?: string }, -): TransformStream => - rscHtmlStreamServer.injectRSCPayload(stream, options) diff --git a/packages/plugin-rsc/tsdown.config.ts b/packages/plugin-rsc/tsdown.config.ts index a385c8377..896808538 100644 --- a/packages/plugin-rsc/tsdown.config.ts +++ b/packages/plugin-rsc/tsdown.config.ts @@ -15,13 +15,8 @@ export default defineConfig({ 'src/react/browser.ts', 'src/react/ssr.ts', 'src/react/rsc.ts', - 'src/extra/browser.tsx', - 'src/extra/ssr.tsx', - 'src/extra/rsc.tsx', 'src/transforms/index.ts', 'src/plugins/cjs.ts', - 'src/rsc-html-stream/ssr.ts', - 'src/rsc-html-stream/browser.ts', 'src/utils/rpc.ts', 'src/utils/encryption-runtime.ts', ], diff --git a/packages/plugin-rsc/types/index.d.ts b/packages/plugin-rsc/types/index.d.ts index ea900dcc0..6f19dd7a6 100644 --- a/packages/plugin-rsc/types/index.d.ts +++ b/packages/plugin-rsc/types/index.d.ts @@ -1,11 +1,7 @@ -import './virtual' - declare global { interface ImportMeta { readonly viteRsc: { loadCss: (importer?: string) => import('react').ReactNode - /** @deprecated use `loadModule("ssr", entry)` instead */ - loadSsrModule: (entry: string) => Promise loadModule: (environmentName: string, entryName: string) => Promise loadBootstrapScriptContent: (entryName: string) => Promise } diff --git a/packages/plugin-rsc/types/virtual.d.ts b/packages/plugin-rsc/types/virtual.d.ts deleted file mode 100644 index cf9ba0ccc..000000000 --- a/packages/plugin-rsc/types/virtual.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module 'virtual:vite-rsc/bootstrap-script-content' { - /** @deprecated use `import.meta.viteRsc.loadBootstrapScriptContent("index")` instead */ - const bootstrapScriptContent: string - export default bootstrapScriptContent -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index df022fd61..7e1ab0494 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -490,9 +490,6 @@ importers: react-server-dom-webpack: specifier: ^19.1.1 version: 19.1.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - rsc-html-stream: - specifier: ^0.0.7 - version: 0.0.7 tinyexec: specifier: ^1.0.1 version: 1.0.1 @@ -597,6 +594,9 @@ importers: connect: specifier: ^3.7.0 version: 3.7.0 + rsc-html-stream: + specifier: ^0.0.7 + version: 0.0.7 sirv: specifier: ^3.0.2 version: 3.0.2