Vue Demi is a developing utility that allows you to write Universal Vue Libraries for Vue 2 & 3
—
Universal access to Composition API functions that work across Vue 2 (with @vue/composition-api) and Vue 3. Vue Demi automatically provides the appropriate implementation based on the detected Vue version.
Ensures the Composition API plugin is properly installed. This is a no-op in Vue 3 but safely installs @vue/composition-api in Vue 2 environments.
/**
* Safe installation of Composition API plugin
* No-op in Vue 3, installs @vue/composition-api in Vue 2
* @param vue - Optional Vue constructor (Vue 2 only), ignored in Vue 3
*/
declare function install(vue?: typeof Vue): void; // Vue 2: (vue?: typeof Vue), Vue 3: () => voidUsage Examples:
import { install } from "vue-demi";
// Ensure Composition API is available
install();
// Or with specific Vue instance
import Vue from 'vue';
install(Vue);
// Safe to call multiple times
install();
install(); // No-op if already installedAll Composition API functions are re-exported from vue-demi, providing a universal interface that works across Vue versions.
// Core reactivity
export function ref<T>(value: T): Ref<T>;
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>;
export function computed<T>(getter: () => T): ComputedRef<T>;
export function readonly<T>(target: T): DeepReadonly<T>;
// Watchers
export function watch<T>(
source: WatchSource<T>,
callback: WatchCallback<T>,
options?: WatchOptions
): WatchStopHandle;
export function watchEffect(
effect: WatchEffect,
options?: WatchOptionsBase
): WatchStopHandle;
// Lifecycle hooks
export function onMounted(hook: () => any): void;
export function onUpdated(hook: () => any): void;
export function onUnmounted(hook: () => any): void;
export function onBeforeMount(hook: () => any): void;
export function onBeforeUpdate(hook: () => any): void;
export function onBeforeUnmount(hook: () => any): void;
// Dependency injection
export function provide<T>(key: InjectionKey<T> | string, value: T): void;
export function inject<T>(key: InjectionKey<T> | string): T | undefined;
export function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T;
// Component utilities
export function getCurrentInstance(): ComponentInternalInstance | null;
export function nextTick(fn?: () => void): Promise<void>;
export function hasInjectionContext(): boolean;Usage Examples:
import {
ref,
reactive,
computed,
watch,
onMounted,
install
} from "vue-demi";
// Ensure Composition API is installed
install();
export default {
setup() {
// Reactive state
const count = ref(0);
const user = reactive({
name: 'John',
email: 'john@example.com'
});
// Computed values
const doubleCount = computed(() => count.value * 2);
// Watchers
watch(count, (newVal, oldVal) => {
console.log(`Count changed from ${oldVal} to ${newVal}`);
});
// Lifecycle
onMounted(() => {
console.log('Component mounted');
});
return {
count,
user,
doubleCount
};
}
};In Vue 2 environments, Vue 3 specific components are provided as mock implementations that throw helpful errors to prevent runtime issues.
/**
* Mock components for Vue 3 features not available in Vue 2
* These throw descriptive errors when used in Vue 2
*/
export declare const Fragment: Component;
export declare const Transition: Component;
export declare const TransitionGroup: Component;
export declare const Teleport: Component;
export declare const Suspense: Component;
export declare const KeepAlive: Component;Usage Examples:
import { Fragment, isVue2 } from "vue-demi";
// Safe conditional usage
const MyComponent = {
setup() {
if (isVue2) {
// Vue 2 implementation without Fragment
return () => h('div', [
h('p', 'First paragraph'),
h('p', 'Second paragraph')
]);
} else {
// Vue 3 implementation with Fragment
return () => h(Fragment, [
h('p', 'First paragraph'),
h('p', 'Second paragraph')
]);
}
}
};
// This would throw an error in Vue 2:
// [vue-demi] Fragment is not supported in Vue 2. It's provided to avoid compiler errors.Utility to check if injection context is available, useful for safely using provide/inject.
/**
* Check if injection context exists
* Falls back to getCurrentInstance() check
* @returns boolean indicating if injection context is available
*/
export function hasInjectionContext(): boolean;Usage Examples:
import { hasInjectionContext, inject, provide } from "vue-demi";
// Safe injection usage
function useTheme() {
if (hasInjectionContext()) {
return inject('theme', 'light');
}
return 'light'; // fallback
}
// Conditional provide/inject
export default {
setup() {
if (hasInjectionContext()) {
provide('theme', 'dark');
}
const theme = useTheme();
return { theme };
}
};Vue 2.7 provides access to Vue's internal warning utility for development debugging.
/**
* Vue warning function (Vue 2.7 only)
* Emits development warnings with optional component context
* @param msg - Warning message to display
* @param vm - Optional component instance for context
*/
export declare function warn(msg: string, vm?: Component | null): void;Usage Examples:
import { warn, isVue2, version } from "vue-demi";
// Development warnings (Vue 2.7 only)
export default {
setup() {
if (process.env.NODE_ENV !== 'production' && isVue2 && version?.startsWith('2.7')) {
// Emit warning with component context
warn('This is a development warning', getCurrentInstance());
// Simple warning
warn('Configuration issue detected');
}
return {};
}
};
// Conditional warning utility
function devWarn(message: string, component?: any) {
if (process.env.NODE_ENV !== 'production' && typeof warn === 'function') {
warn(message, component);
} else {
console.warn(message);
}
}For Vue 2.7, vue-demi provides a polyfill for Vue 3's createApp API.
/**
* Create Vue 3 style app instance (Vue 2.7 only)
* Polyfill that wraps Vue 2 constructor with Vue 3 app interface
*/
export function createApp(rootComponent: any, rootProps?: any): App;
interface App<T = any> {
config: VueConstructor['config'];
use: VueConstructor['use'];
mixin: VueConstructor['mixin'];
component: VueConstructor['component'];
directive(name: string): Directive | undefined;
directive(name: string, directive: Directive): this;
provide<T>(key: InjectionKey<T> | string, value: T): this;
mount: Vue['$mount'];
unmount: Vue['$destroy'];
}Usage Examples (Vue 2.7 only):
import { createApp, isVue2 } from "vue-demi";
const MyComponent = {
template: '<div>{{ message }}</div>',
data() {
return { message: 'Hello Vue!' };
}
};
// Vue 2.7 with createApp polyfill
if (isVue2) {
const app = createApp(MyComponent);
app.provide('theme', 'dark');
app.mount('#app');
}Install with Tessl CLI
npx tessl i tessl/npm-vue-demi