[PR #527] [MERGED] fix: use server closure variable collision with local declarations #647

Closed
opened 2026-05-06 13:09:18 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/527
Author: @james-elicx
Created: 3/13/2026
Status: Merged
Merged: 3/16/2026
Merged by: @james-elicx

Base: mainHead: opencode/curious-tiger


📝 Commits (10+)

  • 26b73ba fix: use server closure variable collision with local declarations
  • ddcd284 fix type error
  • dab3bf8 address comments
  • fb6e175 more tweaks
  • a966383 more tweaks
  • 3cb7bcc more tweaks
  • 12c80f2 fix: address remaining edge cases in use-server-closure-collision plugin
  • 2b561c2 fix: handle ClassDeclaration in collectAllDeclaredNames
  • a14a1a0 Merge remote-tracking branch 'origin/main' into opencode/curious-tiger
  • d6ca338 chore: update test imports to vite-plus/test and vite-plus

📊 Changes

2 files changed (+1410 additions, -0 deletions)

View changed files

📝 packages/vinext/src/index.ts (+444 -0)
tests/use-server-closure-collision.test.ts (+966 -0)

📄 Description

This was observed in the wild with Payload CMS.

Fix

Add a "pre"-enforced Vite plugin (vinext:fix-use-server-closure-collision) that runs before plugin-rsc sees the file. For any "use server" function whose body declares a variable that shadows an outer-scope name, it renames the inner declaration and all its usages within that function body to __local_<name>. The outer binding is untouched.

After the rename, periscopic no longer sees cookies referenced inside the action, so it is not added to bindVars at all. Only genuinely-closed-over variables (like config, which is not redeclared inside the action) remain.

Tests

  • tests/use-server-closure-collision.test.ts — unit tests that exercise the plugin transform directly:
    • Reproduces the bug by calling transformHoistInlineDirective on raw source and confirming the duplicate declaration
    • Verifies the fix eliminates the collision and produces correct output
    • Regression guard for the non-colliding case

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/527 **Author:** [@james-elicx](https://github.com/james-elicx) **Created:** 3/13/2026 **Status:** ✅ Merged **Merged:** 3/16/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `opencode/curious-tiger` --- ### 📝 Commits (10+) - [`26b73ba`](https://github.com/cloudflare/vinext/commit/26b73ba53065d0af125162edba40c73e06a5edc9) fix: `use server` closure variable collision with local declarations - [`ddcd284`](https://github.com/cloudflare/vinext/commit/ddcd28467770073350759dbbbf6474681164b1c5) fix type error - [`dab3bf8`](https://github.com/cloudflare/vinext/commit/dab3bf86ab4649c14f69bf0635f7c453ca9a72ed) address comments - [`fb6e175`](https://github.com/cloudflare/vinext/commit/fb6e175bf53428df2d5341b25c1e66d7de2fe75d) more tweaks - [`a966383`](https://github.com/cloudflare/vinext/commit/a966383c642747eed162a989f886eba45b0b94c5) more tweaks - [`3cb7bcc`](https://github.com/cloudflare/vinext/commit/3cb7bcc5f3b3f2871516bd4aee8bb35079f7b3ac) more tweaks - [`12c80f2`](https://github.com/cloudflare/vinext/commit/12c80f2447844dd1efeed18cbd89bc65484b3566) fix: address remaining edge cases in use-server-closure-collision plugin - [`2b561c2`](https://github.com/cloudflare/vinext/commit/2b561c2e5e35225f9a8479e65d3656da4c391083) fix: handle ClassDeclaration in collectAllDeclaredNames - [`a14a1a0`](https://github.com/cloudflare/vinext/commit/a14a1a0122701cfcccbf5e1503c96102203bd3b8) Merge remote-tracking branch 'origin/main' into opencode/curious-tiger - [`d6ca338`](https://github.com/cloudflare/vinext/commit/d6ca33862253bed06813c96e297e05e24212197f) chore: update test imports to vite-plus/test and vite-plus ### 📊 Changes **2 files changed** (+1410 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/index.ts` (+444 -0) ➕ `tests/use-server-closure-collision.test.ts` (+966 -0) </details> ### 📄 Description This was observed in the wild with Payload CMS. ### Fix Add a `"pre"`-enforced Vite plugin (`vinext:fix-use-server-closure-collision`) that runs before `plugin-rsc` sees the file. For any `"use server"` function whose body declares a variable that shadows an outer-scope name, it renames the inner declaration **and all its usages within that function body** to `__local_<name>`. The outer binding is untouched. After the rename, `periscopic` no longer sees `cookies` referenced inside the action, so it is not added to `bindVars` at all. Only genuinely-closed-over variables (like `config`, which is not redeclared inside the action) remain. ### Tests - `tests/use-server-closure-collision.test.ts` — unit tests that exercise the plugin transform directly: - Reproduces the bug by calling `transformHoistInlineDirective` on raw source and confirming the duplicate declaration - Verifies the fix eliminates the collision and produces correct output - Regression guard for the non-colliding case --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:09:18 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#647
No description provided.