Skip to content

fix(rsc): handle conflict names from export * in use client and use server modules#1239

Merged
hi-ogawa merged 54 commits into
mainfrom
ho/extract-export-all-transform
Jun 1, 2026
Merged

fix(rsc): handle conflict names from export * in use client and use server modules#1239
hi-ogawa merged 54 commits into
mainfrom
ho/extract-export-all-transform

Conversation

@hi-ogawa
Copy link
Copy Markdown
Contributor

@hi-ogawa hi-ogawa commented May 29, 2026

Description

This PR extracts export * expansion into a dedicated transform with file fixtures based unti tests and tightens its handling of ESM star-export ambiguity before downstream proxy/wrap transforms run.

It turned out export * semantics have many edge cases and some cases are explicitly not handled yet but kept as test cases with TODOs, for example:

  • Support duplicate export * entries that resolve to the same underlying binding instead of treating them as ambiguous.
  • Support duplicate namespace re-exports that resolve to the same namespace binding.
  • Replace the current cycle bailout with per-name/per-binding resolution so cyclic star exports that resolve to the same binding can survive.
  • Support string-literal export names instead of rejecting them.
  • Preserve/compose source maps for the pre-rewrite transform.

hi-ogawa and others added 21 commits May 29, 2026 16:33
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
@hi-ogawa hi-ogawa changed the title fix(rsc): tweak export * handling with use client and use server fix(rsc): tweak export * re-export handling with use client and use server modules May 29, 2026
@hi-ogawa hi-ogawa self-assigned this May 29, 2026
Co-authored-by: Codex <noreply@openai.com>
@hi-ogawa hi-ogawa changed the title fix(rsc): tweak export * re-export handling with use client and use server modules fix(rsc): handle conflict names from export * in use client and use server modules May 29, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves @vitejs/plugin-rsc’s handling of export * from ... inside "use client" and "use server" modules by introducing a pre-transform that expands bare star re-exports into explicit named re-exports, including logic to avoid re-exporting ambiguous/conflicting names (per ESM rules). It also adds/updates tests and fixtures around export scanning/expansion and tightens behavior for unsupported string-literal export names.

Changes:

  • Add transformExpandExportAll to recursively scan dependencies and rewrite bare export * from into explicit export { ... } from before proxy/wrap transforms run.
  • Update proxy/wrap transforms to throw a clearer error for string-literal export names.
  • Add unit fixtures/tests and an e2e route/test covering "use server" + export * server actions.

Reviewed changes

Copilot reviewed 76 out of 76 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
packages/plugin-rsc/src/transforms/wrap-export.ts Throw clearer error for string-literal export names; simplify ExportAllDeclaration handling.
packages/plugin-rsc/src/transforms/wrap-export.test.ts Add test for string-literal export-name error; adjust export * as snapshot expectation.
packages/plugin-rsc/src/transforms/utils.ts Remove getExportNames helper (no longer used).
packages/plugin-rsc/src/transforms/proxy-export.ts Throw clearer error for string-literal export names.
packages/plugin-rsc/src/transforms/proxy-export.test.ts Add test for string-literal export-name error.
packages/plugin-rsc/src/transforms/index.ts Re-export new expand-export-all transform from transforms entrypoint.
packages/plugin-rsc/src/transforms/expand-export-all.ts New recursive scanner/rewriter to expand bare export * into explicit named re-exports with conflict/ambiguity handling.
packages/plugin-rsc/src/transforms/expand-export-all.test.ts Fixture-driven tests validating transformExpandExportAll rewrites and error cases.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/string-export-name/entry.js.snap.js Snapshot for string-literal export-name error case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/string-export-name/entry.js Fixture entry for string-literal export-name error case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/string-export-name/dep.js Fixture dependency exporting a string-literal export name.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/no-export-star/entry.js.snap.js Snapshot for “no bare export-star to expand” case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/no-export-star/entry.js Fixture with export * as ns (should not be rewritten).
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/no-export-star/dep.js Fixture dep for “no-export-star” case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-filtered-conflict/repro2.js Extra repro script for conflict behavior notes.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-filtered-conflict/repro1.js Extra repro script for Node/V8 behavior notes.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-filtered-conflict/entry.js.snap.js Snapshot for nested filtered conflict expansion.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-filtered-conflict/entry.js Fixture entry re-exporting from two deps.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-filtered-conflict/dep2.js Fixture dep with nested export * chain.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-filtered-conflict/dep2-2.js Fixture leaf dep for nested chain.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-filtered-conflict/dep2-1.js Fixture leaf dep for nested chain.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-filtered-conflict/dep1.js Fixture dep for nested conflict case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-star/entry.js.snap.js Snapshot for nested conflict-star expansion.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-star/entry.js Fixture entry with export * to dep that re-exports conflicting names.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-star/dep.js Fixture dep that star-exports from two modules.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-star/b.js Fixture leaf module.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-star/a.js Fixture leaf module.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-explicit-reexport-wins/override.js Fixture override module for explicit re-export precedence.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-explicit-reexport-wins/middle.js Fixture middle module combining star + explicit re-export.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-explicit-reexport-wins/entry.js.snap.js Snapshot for explicit re-export precedence through nesting.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-explicit-reexport-wins/entry.js Fixture entry for precedence case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-explicit-reexport-wins/dep.js Fixture dep with star re-exports.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-explicit-reexport-wins/b.js Fixture leaf module.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/nested-conflict-explicit-reexport-wins/a.js Fixture leaf module.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/namespace-same-binding/entry.js.snap.js Snapshot capturing current limitation for same-binding namespace duplication.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/namespace-same-binding/entry.js Fixture entry for same-binding namespace duplication.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/namespace-same-binding/dep2.js Fixture dep exporting namespace from same target.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/namespace-same-binding/dep1.js Fixture dep exporting namespace from same target.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/namespace-same-binding/dep-target.js Shared target module for namespace exports.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/explicit-wins/entry.js.snap.js Snapshot for explicit local export shadowing star export.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/explicit-wins/entry.js Fixture entry for explicit-shadowing case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/explicit-wins/dep.js Fixture dep for explicit-shadowing case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/duplicate-star-same-source/entry.js.snap.js Snapshot capturing current limitation for duplicate star exports from same source.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/duplicate-star-same-source/entry.js Fixture entry repeating the same export * from multiple times.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/duplicate-star-same-source/dep.js Fixture dep for duplicate-star case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/default-only/entry.js.snap.js Snapshot for star re-export of default-only module (results in empty named re-export).
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/default-only/entry.js Fixture entry for default-only case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/default-only/dep.js Fixture dep exporting only default (plus side effects).
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/conflict-star/entry.js.snap.js Snapshot for conflicting names across multiple star sources.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/conflict-star/entry.js Fixture entry for conflict-star case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/conflict-star/b.js Fixture leaf module.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/conflict-star/a.js Fixture leaf module.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/circular/entry.js.snap.js Snapshot for circular star export graph case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/circular/entry.js Fixture entry for circular case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/circular/dep2.js Fixture dep in circular chain.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/circular/dep1.js Fixture dep in circular chain.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/circular-same-binding/entry.js.snap.js Snapshot capturing current limitation for cyclic same-binding case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/circular-same-binding/entry.js Fixture entry for cyclic same-binding case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/circular-same-binding/b.js Fixture dep in cyclic case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/circular-same-binding/a.js Fixture dep in cyclic case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/basic/nested.js Fixture nested module exporting a class.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/basic/entry.js.snap.js Snapshot for basic expansion (incl. namespace + nested star).
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/basic/entry.js Fixture entry for basic expansion.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/basic/dep.js Fixture dep combining explicit exports, default re-export, star, and namespace export.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/basic/default.js Fixture default-export module.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/bad-resolve/entry.js.snap.js Snapshot for “failed to resolve” error.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/bad-resolve/entry.js Fixture entry for “bad resolve” case.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/bad-load/entry.js.snap.js Snapshot for “failed to load” error.
packages/plugin-rsc/src/transforms/fixtures/expand-export-all/bad-load/entry.js Fixture entry for “bad load” case.
packages/plugin-rsc/src/plugin.ts Use transformExpandExportAll in both use client and use server plugin transforms.
packages/plugin-rsc/examples/basic/src/routes/root.tsx Wire new example route into the basic example app.
packages/plugin-rsc/examples/basic/src/routes/action-export-all/server.tsx New server component exercising use server + export * server actions.
packages/plugin-rsc/examples/basic/src/routes/action-export-all/client.tsx New client component invoking server action through expanded re-export.
packages/plugin-rsc/examples/basic/src/routes/action-export-all/actions.ts use server module that re-exports actions via bare export *.
packages/plugin-rsc/examples/basic/src/routes/action-export-all/action-impl.ts Action implementations to be re-exported and registered.
packages/plugin-rsc/e2e/basic.test.ts Add e2e coverage for use server + export *; rename existing “export *” test label.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/plugin-rsc/src/transforms/wrap-export.ts
Comment thread packages/plugin-rsc/src/transforms/wrap-export.ts
Comment thread packages/plugin-rsc/src/transforms/proxy-export.ts
Comment thread packages/plugin-rsc/src/transforms/expand-export-all.ts
Comment thread packages/plugin-rsc/src/transforms/expand-export-all.ts
Comment thread packages/plugin-rsc/src/transforms/wrap-export.ts
Comment thread packages/plugin-rsc/src/transforms/wrap-export.ts
Comment thread packages/plugin-rsc/src/transforms/proxy-export.ts
Comment thread packages/plugin-rsc/src/transforms/expand-export-all.ts
Comment thread packages/plugin-rsc/src/transforms/expand-export-all.ts
Co-authored-by: Codex <noreply@openai.com>
@hi-ogawa hi-ogawa marked this pull request as ready for review June 1, 2026 08:05
@hi-ogawa

This comment was marked as outdated.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 76 out of 76 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (2)

packages/plugin-rsc/src/transforms/wrap-export.ts:193

  • transformWrapExport no longer handles export * as ns from "..." (ExportAllDeclaration with exported identifier). This is still a valid ESM form and is already supported by transformProxyExport; dropping support here will make use server wrapping (transformServerActionServer -> transformWrapExport) throw unsupported ExportAllDeclaration for namespace re-exports.
    packages/plugin-rsc/src/transforms/proxy-export.ts:118
  • expand-export-all can rewrite a star export into export {} from "..." to preserve side effects when no names are safely re-exportable. transformProxyExport currently treats any ExportNamedDeclaration with specifiers as something to replace with proxy exports; when specifiers is empty it replaces the whole statement with an empty string, dropping the side-effect-only re-export. export {} from should be left intact.

Comment thread packages/plugin-rsc/src/transforms/wrap-export.ts
Comment thread packages/plugin-rsc/src/transforms/wrap-export.test.ts
toAppend.push(`import * as ${localName} from ${node.source.raw}`)
wrapExport(localName, exportedName)
} else if (!options.ignoreExportAllDeclaration) {
if (!options.ignoreExportAllDeclaration) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was reverted since this change was irrelevant for original PR

@hi-ogawa hi-ogawa merged commit d618f63 into main Jun 1, 2026
24 checks passed
@hi-ogawa hi-ogawa deleted the ho/extract-export-all-transform branch June 1, 2026 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants