Environment
unplugin@3.0.0 + bun@1.3.13
Reproduction
// repro.ts — run with `bun repro.ts`
import { createBunPlugin } from 'unplugin'
await Bun.write('./entry.ts', "import x from 'virtual:foo'; console.log(x);\n")
const plugin = createBunPlugin(() => ({
name: 'my:plugin', // ← colon
resolveId(id) {
return id === 'virtual:foo' ? id : null
},
load(id) {
return id === 'virtual:foo' ? 'export default 1' : null
},
}))()
await Bun.build({
entrypoints: ['./entry.ts'],
plugins: [plugin],
})
Describe the bug
When an unplugin plugin defines both resolveId and load, the Bun adapter treats it as a virtual-module provider and uses plugin.name directly as the namespace passed to build.onLoad. Bun's namespace validator only accepts characters in [$a-zA-Z0-9_-] (oven-sh/bun:src/js/builtins/BundlerPlugin.ts#L215-217).
Plugin names elsewhere in the unplugin/rollup/vite ecosystem commonly use : as a scope separator (e.g. tanstack-router:code-splitter:compile-virtual-file), so the raw name fails Bun's validator and crashes any plugin that virtualises modules.
Additional context
No response
Logs
201 | });
202 | for (const pluginName of virtualModulePlugins) build.onLoad({
^
TypeError: namespace can only contain $a-zA-Z0-9_\-
at validate (4:20)
at onLoad (32:18)
at setup (node_modules/unplugin/dist/index.mjs:202:58)
at repro.ts:16:11
Environment
unplugin@3.0.0 + bun@1.3.13
Reproduction
Describe the bug
When an unplugin plugin defines both
resolveIdandload, the Bun adapter treats it as a virtual-module provider and usesplugin.namedirectly as the namespace passed tobuild.onLoad. Bun's namespace validator only accepts characters in[$a-zA-Z0-9_-](oven-sh/bun:src/js/builtins/BundlerPlugin.ts#L215-217).Plugin names elsewhere in the unplugin/rollup/vite ecosystem commonly use
:as a scope separator (e.g.tanstack-router:code-splitter:compile-virtual-file), so the raw name fails Bun's validator and crashes any plugin that virtualises modules.Additional context
No response
Logs