Skip to content

fix(plugin-vue): disable oxc jsx.refresh for Vue SFCs to prevent React Fast Refresh injection (fix #798) - #814

Open
AmariahAK wants to merge 1 commit into
vitejs:mainfrom
AmariahAK:main
Open

fix(plugin-vue): disable oxc jsx.refresh for Vue SFCs to prevent React Fast Refresh injection (fix #798)#814
AmariahAK wants to merge 1 commit into
vitejs:mainfrom
AmariahAK:main

Conversation

@AmariahAK

Copy link
Copy Markdown

What is this PR solving?

When @vitejs/plugin-react is present in the same Vite config, it sets
config.oxc.jsx.refresh = true globally. The Vue plugin's TS transpilation
step in transformMain blindly spreads the full config.oxc into
transformWithOxc, causing Oxc to inject $RefreshSig$ / $RefreshReg$
into Vue SFCs with <script setup lang="ts"> that use use* composables
(e.g. useSlots(), useRoute(), useStore()). On Vue-only pages these
globals don't exist, causing ReferenceError: $RefreshSig$ is not defined.
The fix explicitly overrides jsx.refresh to false in the Oxc transform
options for Vue SFCs, while preserving all other oxc config inheritance
(e.g. target for decorators support per #430).

What alternatives have been explored?

  • Not spreading config.oxc at all, cherry-picking specific options only:
    Would break the existing behavior of inheriting user-configured oxc options
    like target. Also fragile against future oxc option additions.
  • Blanking jsx entirely (jsx: undefined):
    Too aggressive — users with .tsx Vue components may have legitimate JSX
    config they want to flow through.
  • Chosen approach — override only jsx.refresh:
    Surgical. Preserves all other oxc config inheritance while blocking the
    single problematic option. Self-documenting: makes it obvious that React
    Fast Refresh has no place in Vue SFC transforms.

Are there any parts that require more attention from reviewers?

The fix is a four-line addition. The key consideration is whether there are
other Oxc options beyond jsx.refresh that @vitejs/plugin-react or similar
React tooling might set globally that could also leak into Vue SFCs. I believe
refresh is the only one with this characteristic — other JSX options like
jsxRuntime and importSource are React-specific and wouldn't produce
meaningful output for .vue files anyway.

Tests included

A new test playground playground/vue-refresh-bug/ with:

  • vite.config.ts setting oxc.jsx.refresh = true (simulating
    @vitejs/plugin-react)
  • RefreshBug.vue<script setup lang="ts"> calling useSlots()
  • Two assertions: component renders without errors, and no $RefreshSig$
    or $RefreshReg$ appear in browser logs/page errors
    Full test suite (pnpm test-serve + pnpm test-build): 13 files, 104 tests,
    zero regressions.

…t Fast Refresh injection (fix vitejs#798)

When @vitejs/plugin-react is present in the same Vite config, it sets
config.oxc.jsx.refresh = true globally. The Vue plugin's TS transpilation
step in transformMain blindly spreads the full config.oxc into
transformWithOxc, causing Oxc to inject $RefreshSig$ / $RefreshReg$
into Vue SFCs with <script setup lang="ts"> that use use* composables.
On Vue-only pages this causes ReferenceError at runtime.

The fix explicitly overrides jsx.refresh to false in the Oxc transform
options for Vue SFCs, preserving all other oxc config inheritance.

Co-authored-by: atlarix-agent <agent@atlarix.dev>
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