@eckidevs/bun-plugin-vue
Advanced tools
Comparing version
{ | ||
"name": "@eckidevs/bun-plugin-vue", | ||
"version": "0.0.3", | ||
"version": "0.1.0", | ||
"module": "src/index.ts", | ||
@@ -5,0 +5,0 @@ "main": "src/index.ts", |
@@ -67,22 +67,47 @@ # Bun Plugin Vue | ||
## Plugin Options | ||
The plugin has optional settings that you can pass: | ||
```ts | ||
interface VuePluginOptions { | ||
prodDevTools?: boolean; // Default = false | ||
optionsApi?: boolean; // Default = false | ||
prodHydrationMismatchDetails?: boolean; // Default = false | ||
} | ||
``` | ||
- `prodDevTools`: If set to `true`, it will enable Vue DevTools in production mode. This is useful for debugging but may expose sensitive information, so use with caution. | ||
- `optionsApi`: If set to `true`, it will enable the Options API in Vue. This is useful if you want to use the Options API instead of the Composition API. | ||
- `prodHydrationMismatchDetails`: If set to `true`, it will provide detailed error messages for hydration mismatches in production mode. This is useful for debugging hydration issues but may expose sensitive information, so use with caution. | ||
## Known Issues | ||
You might encouter the following console message in the browser (in development): | ||
- `Feature flags __VUE_OPTIONS_API__, __VUE_PROD_DEVTOOLS__, __VUE_PROD_HYDRATION_MISMATCH_DETAILS__` | ||
### Hot Reloading Error Logs | ||
This is because the `define` option in bun's config is not yet supported in the dev server. You could suppress it by adding in your HTML: | ||
Because bun implements hot reloading in the Full-Stack Dev Server to eliminate | ||
HMR error logs, add the following to the main.ts where your vue app is created: | ||
```html | ||
<script> | ||
globalThis.__VUE_OPTIONS_API__ = true; | ||
globalThis.__VUE_PROD_DEVTOOLS__ = false; | ||
globalThis.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = false; | ||
</script> | ||
```ts | ||
import { createApp } from 'vue'; | ||
import App from './App.vue'; | ||
const app = createApp(App); | ||
// The important part for HMR | ||
if (import.meta.hot) { | ||
import.meta.hot.on('bun:invalidate', () => { | ||
app.unmount(); | ||
}) | ||
import.meta.hot.accept() | ||
} | ||
app.mount('#app'); | ||
``` | ||
That is not the correct fix though, it needs to be replaced in the code at compile time. | ||
This will be fixed in a future version of Bun. | ||
This HMR code will be dead-code eliminated during production. | ||
@@ -5,3 +5,5 @@ import type { BunPlugin } from 'bun'; | ||
interface VuePluginOptions { | ||
// Reserve for future options (like SSR) | ||
prodDevTools?: boolean; | ||
optionsApi?: boolean; | ||
prodHydrationMismatchDetails?: boolean; | ||
} | ||
@@ -11,13 +13,19 @@ | ||
// the dev server does not actually respect config mutation. | ||
function setVueCompileTimeFlags(build: Bun.PluginBuilder) { | ||
function setVueCompileTimeFlags(build: Bun.PluginBuilder, options: VuePluginOptions) { | ||
build.config.define ??= {} | ||
build.config.define['__VUE_PROD_DEVTOOLS__'] = 'false'; | ||
build.config.define['__VUE_OPTIONS_API__'] = 'true'; | ||
build.config.define['__VUE_PROD_HYDRATION_MISMATCH_DETAILS__'] = 'false'; | ||
build.config.define['__VUE_PROD_DEVTOOLS__'] = options.prodDevTools === false ? 'false' : 'true'; | ||
build.config.define['__VUE_OPTIONS_API__'] = options.optionsApi === false ? 'false' : 'true'; | ||
build.config.define['__VUE_PROD_HYDRATION_MISMATCH_DETAILS__'] = options.prodHydrationMismatchDetails === false ? 'false' : 'true'; | ||
} | ||
export default function plugin(options?: VuePluginOptions): BunPlugin { | ||
// TODO: more options | ||
if (options) {}; | ||
const opts = options || {}; | ||
// Set default options | ||
Object.assign(opts, { | ||
prodDevTools: opts.prodDevTools ?? false, | ||
optionsApi: opts.optionsApi ?? false, | ||
prodHydrationMismatchDetails: opts.prodHydrationMismatchDetails ?? false, | ||
}) | ||
return { | ||
@@ -27,3 +35,3 @@ name: 'vue', | ||
if (Bun.env.NODE_ENV !== 'production') { | ||
setVueCompileTimeFlags(build); | ||
setVueCompileTimeFlags(build, opts); | ||
} | ||
@@ -189,2 +197,40 @@ | ||
}); | ||
const replacedMap = new Map<string, string>(); | ||
build.onLoad({ filter: /node_modules\/@vue\/(.*)\.js$/ }, async (args) => { | ||
const file = Bun.file(args.path); | ||
let source = await file.text(); | ||
const replaced = replacedMap.get(args.path); | ||
if (replaced) { | ||
return { | ||
contents: replaced, | ||
loader: 'js', | ||
} | ||
} | ||
// Replace Vue Feature Flags | ||
// This is a workaround for Bun's lack of support for define in dev | ||
const vueFlags = { | ||
'__VUE_PROD_DEVTOOLS__': opts.prodDevTools ? 'true' : 'false', | ||
'__VUE_OPTIONS_API__': opts.optionsApi ? 'true' : 'false', | ||
'__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': opts.prodHydrationMismatchDetails ? 'true' : 'false', | ||
}; | ||
Object.entries(vueFlags).forEach(([key, value]) => { | ||
const rgx = new RegExp(`${key}`, 'g'); | ||
source = source.replace(rgx, value); | ||
}); | ||
// TODO: These are big strings being cached | ||
// We should consider a more efficient caching strategy | ||
replacedMap.set(args.path, source); | ||
return { | ||
contents: source, | ||
loader: 'js', | ||
} | ||
}) | ||
} | ||
@@ -191,0 +237,0 @@ } |
18468
14.78%221
20.11%113
28.41%