Skip to content

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

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions