Skip to content

plugin-vue-jsx: __file not injected on JSX/TSX components, breaking Vue DevTools 'Open in Editor' #783

@NikhilVerma

Description

@NikhilVerma

Summary

@vitejs/plugin-vue injects __file on every SFC component in development, which Vue DevTools uses to show the Open in Editor button and to resolve component file paths. @vitejs/plugin-vue-jsx never injects __file, so this button is always absent for JSX/TSX components regardless of how they are defined.

Reproduction

Any Vue app using JSX/TSX components. Select a TSX component in Vue DevTools — the Open in Editor icon (⬡) is missing from the component panel header because instance.type.__file is undefined.

Root cause

@vitejs/plugin-vue (line ~1657 of its dist):

// Injected on every SFC in dev or when devToolsEnabled:
if (devToolsEnabled || (devServer && !isProduction))
  attachedProps.push(['__file', JSON.stringify(isProduction ? path.basename(filename) : filename)])

@vitejs/plugin-vue-jsx has no equivalent. Its only devtools-related injection is __hmrId, and even that is limited to components detected via parseComponentDecls — which only matches defineComponent() call expressions. Plain function/arrow components receive nothing.

// plugin-vue-jsx/dist/index.js ~line 161-163
// hotComponents is only populated when defineComponent() is detected
for (const { local, exported, id: id$1 } of hotComponents) {
  code$1 += `\n${local}.__hmrId = "${id$1}"\n__VUE_HMR_RUNTIME__.createRecord("${id$1}", ${local})`
  // __file is never written here or anywhere else in the plugin
}

So the current behaviour is:

Pattern __hmrId __file
.vue SFC
.tsx with defineComponent()
.tsx plain function/arrow

Expected behaviour

All JSX/TSX components should receive __file in development, matching what plugin-vue does for SFCs. For components already detected by parseComponentDecls, the fix is a one-liner alongside the existing __hmrId injection:

for (const { local, exported, id: id$1 } of hotComponents) {
  code$1 += `\n${local}.__file = ${JSON.stringify(id)}` // add this
  code$1 += `\n${local}.__hmrId = "${id$1}"\n__VUE_HMR_RUNTIME__.createRecord("${id$1}", ${local})`
}

For plain functional components not detected by parseComponentDecls, a broader injection (e.g. based on export declarations) would be needed for full parity.

Notes

  • Verified against @vitejs/plugin-vue-jsx@5.1.1 and @vitejs/plugin-vue@6.0.1
  • @vue/babel-plugin-jsx (used internally by plugin-vue-jsx) also does not inject __file
  • There is no plugin option or workaround to enable this behaviour today
  • Affects Vue DevTools (both the Vite plugin and the Chrome extension), Nuxt DevTools, and any tool that reads instance.type.__file

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