Vue Demi: Universal Vue Library Helper
Vue Demi (French for 'half') is a foundational utility library designed for authors building universal Vue libraries that must operate seamlessly across both Vue 2 and Vue 3 environments. It intelligently abstracts away the underlying Vue version, redirecting common Composition API imports (e.g., `ref`, `reactive`, `defineComponent`) to the appropriate Vue runtime (`vue@2` with `@vue/composition-api` or `vue@3`). The current stable version is `0.14.10`, with a consistent and active release cadence that focuses on compatibility fixes, minor feature enhancements, and addressing edge cases, often seeing several patch releases per month. Its key differentiator is providing a single, unified API surface for Composition API features and core Vue utilities, enabling developers to write code once and deploy it to both major Vue versions without needing conditional imports or complex build setups. It also exposes utilities like `isVue2` and `isVue3` for version-specific logic and a `Vue2` export for safely accessing global Vue 2 APIs (e.g., `Vue.config`, `Vue.set`).
Common errors
-
[plugin:vite:dep-scan] Cannot find module 'vue-demi' or [Vue warn]: Failed to resolve component: ...
cause Vite's dependency pre-bundling interferes with `vue-demi`'s dynamic module resolution.fixAdd `exclude: ['vue-demi']` to the `optimizeDeps` option in your `vite.config.js`. -
TypeError: Vue.use is not a function (in Vue 2) or [Vue warn]: Failed to resolve plugin: CompositionApi
cause The `@vue/composition-api` plugin was not correctly installed in a Vue 2 environment.fixEnsure `@vue/composition-api` is correctly specified as a peer dependency and consider explicitly calling `install()` from `vue-demi` in your library's entry point. -
TypeError: Vue.set is not a function (or Vue.delete is not a function)
cause Attempting to use Vue 2-specific global reactivity methods directly in a Vue 3 environment.fixFor universal code, use reactive assignments or methods like `ref()` and `reactive()`. If Vue 2-specific global API access is needed, use `if (Vue2) { Vue2.set(...) }`. -
ReferenceError: globalThis is not defined
cause Running `vue-demi` in an extremely old browser environment lacking `globalThis` support.fixUpdate to a browser version that supports `globalThis` (e.g., Chrome 52+, Firefox 55+, Edge 15+, Safari 10.1+). Ensure `vue-demi` is updated to at least `0.14.9` which includes compatibility fixes.
Warnings
- breaking Library authors must correctly configure `vue` and `@vue/composition-api` as `peerDependencies` in their `package.json` to ensure `vue-demi` can correctly resolve the user's Vue environment and guide installations.
- gotcha When using `vue-demi` within a Vite project, it must be explicitly excluded from Vite's dependency pre-bundling to prevent module resolution issues and ensure dynamic version switching works correctly.
- gotcha While `vue-demi` typically auto-installs the Composition API plugin for Vue 2 environments, in specific complex plugin setups or environments where auto-installation is unreliable, manual installation might be required.
- gotcha The `Vue2` export from `vue-demi` is provided to access global Vue 2 APIs (like `Vue.set` or `Vue.del`) but will be `undefined` when running in a Vue 3 environment.
- gotcha Older browser environments (pre-Chrome 52 / Firefox 55) may not support `globalThis`, leading to `ReferenceError: globalThis is not defined`.
Install
-
npm install vue-demi -
yarn add vue-demi -
pnpm add vue-demi
Imports
- ref, reactive, defineComponent
import { ref } from 'vue'; import { reactive } from '@vue/composition-api'import { ref, reactive, defineComponent } from 'vue-demi' - isVue2, isVue3, version
if (Vue.version.startsWith('2'))import { isVue2, isVue3, version } from 'vue-demi' - Vue2
import { Vue2 } from 'vue-demi' - install
import { install } from 'vue-demi'
Quickstart
import { ref, computed, isVue2, isVue3, version as vueVersion, getCurrentInstance } from 'vue-demi';
/**
* A universal composable that provides a reactive counter.
* Works across Vue 2 (with Composition API) and Vue 3.
*/
export function useUniversalCounter(initialValue: number = 0) {
const count = ref(initialValue);
const double = computed(() => count.value * 2);
const increment = () => {
count.value++;
};
// Demonstrate version-specific logic
if (isVue2) {
console.log(`[Vue Demi] Running in Vue 2 (version: ${vueVersion}).`);
// Example of accessing Vue 2 instance if needed (caution: not always universal)
const vm = getCurrentInstance()?.proxy;
if (vm) {
console.log('Vue 2 VM detected:', vm.$options.name);
}
} else if (isVue3) {
console.log(`[Vue Demi] Running in Vue 3 (version: ${vueVersion}).`);
// Example of accessing Vue 3 instance (different structure)
const instance = getCurrentInstance();
if (instance) {
console.log('Vue 3 instance detected:', instance.type.name);
}
}
return {
count,
double,
increment,
isVue2,
isVue3,
vueVersion
};
}
// To test in a Vue 3 environment:
// npm install vue@3 vue-demi
// npx vue-demi-switch 3
// Then integrate `useUniversalCounter` into a Vue 3 component.
// To test in a Vue 2 environment (requires Composition API plugin):
// npm install vue@2 @vue/composition-api vue-demi
// npx vue-demi-switch 2
// Make sure @vue/composition-api is installed for Vue 2.6.x.
// Then integrate `useUniversalCounter` into a Vue 2 component.