Skip to content

[plugin-rsc] use-client transform throws on export * from (ExportAllDeclaration) #1233

@james-elicx

Description

@james-elicx

Describe the bug

@vitejs/plugin-rsc's rsc:use-client transform throws

Error: unsupported ExportAllDeclaration
    at transformProxyExport (.../plugin-rsc/dist/transforms/index.js:338:90)

for any "use client" module that re-exports another module with export * from '...' or export * as Ns from '...'. This is a common pattern in real-world React code (barrel files for groups of client components), and it ships in the Next.js rsc-basic e2e suite (components/export-all/), so any Vite/RSC framework that aims to be a drop-in replacement for the Next.js App Router build pipeline hits this immediately.

Reproduction

A "use client" file containing:

"use client";
export * from "./one";

triggers the error during the RSC environment build.

Source

The throw is unconditional once ignoreExportAllDeclaration is false (which is the default for the use-client path):

// dist/transforms/index.js around line 338
if (!options.ignoreExportAllDeclaration && node.type === "ExportAllDeclaration")
  throw new Error("unsupported ExportAllDeclaration");

There is no public option on the use-client plugin to flip this, and the * case isn't routed through the proxy generator.

Expected behavior

export * from '...' and export * as Ns from '...' should be handled inside a "use client" boundary. Two reasonable options:

  1. Resolve at transform time — enumerate the target module's named exports and emit one client-reference proxy per name (skipping default, matching ESM export * semantics).
  2. Forward at module-graph time — leave the declaration in place and let the bundler resolve it natively after the proxies for the target module are emitted. This is conceptually what Next.js's flight loader does: it falls back to assumedSourceType === "module" when clientRefs contains * so webpack handles the re-export (next-flight-loader/index.ts).

Current workaround

In cloudflare/vinext we added a pre-pass plugin that runs before rsc:use-client in the RSC environment, parses each "use client" module, and rewrites:

  • export * from '...'export { a, b, c, ... } from '...' (named exports enumerated by resolving the target via this.resolve + this.load, recursing through chained export *)
  • export * as Ns from '...'import * as Ns from '...'; export { Ns };

Tracking PR: cloudflare/vinext#1373
Plugin source: https://github.com/cloudflare/vinext/blob/fix/issue-1352-use-client-export-all/packages/vinext/src/plugins/use-client-export-all.ts

This works for relative imports inside the user's graph but cannot handle bare-specifier targets that the RSC plugin's package-source path will eventually proxy — those still hit the error.

System info

@vitejs/plugin-rsc@0.5.26 on Vite 8 / Rolldown.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions