Skip to content

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

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/[email protected] on Vite 8 / Rolldown.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions