Skip to content

Bun adapter: load hook cannot override the inferred Loader #600

Description

@81reap

Environment

unplugin@3.0.0 + bun@1.3.13

Reproduction

import { createBunPlugin } from 'unplugin'

await Bun.write(
  './entry.ts',
  "import Hello from 'virtual:component'; console.log(<Hello />);\n",
)

const plugin = createBunPlugin(() => ({
  name: 'jsx-virtual',
  resolveId(id) {
    return id === 'virtual:component' ? id : null
  },
  load(id) {
    if (id === 'virtual:component') {
      return 'export default () => <h1>hi</h1>'
    }
    return null
  },
}))()

await Bun.build({
  entrypoints: ['./entry.ts'],
  plugins: [plugin],
})

Describe the bug

In the Bun adapter, the Loader for a load hook's returned contents is inferred from path.extname(id) via guessLoader (src/bun/utils.ts). The result is passed as the loader field on Bun's onLoad return.

This is fine for 'file' namespace loads where the id is a real file path, but for virtual modules the id has no meaningful extension (or carries a query suffix that confuses extname). Bun then falls back to js, which fails when the plugin's returned contents are JSX/TSX/CSS/etc.

Plugins have no way to tell unplugin "this content is tsx" — the existing LoadResult type only carries code and map. esbuild's own onLoad accepts { contents, loader }; unplugin's Bun adapter should let plugins pass the same hint.

Additional context

No response

Logs

$ bun run 02-loader.ts 
1 | export default () => <h1>hi</h1>
                         ^
error: Unexpected <
    at virtual:component:1:22

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions