Vue 3 compatibility build for Vue 2 that provides configurable Vue 2 compatible behavior to facilitate migration from Vue 2 to Vue 3
—
Helper functions and utilities for managing the migration process, checking compatibility modes, and integrating with Vue 3 features during the transition from Vue 2 to Vue 3.
Collection of utility functions for managing compatibility features and migration process.
declare const compatUtils: {
warnDeprecation: (key: DeprecationTypes, instance, ...args) => void;
isCompatEnabled: (key: DeprecationTypes, instance, enableForBuiltIn?) => boolean;
checkCompatEnabled: (key: DeprecationTypes, instance) => boolean;
softAssertCompatEnabled: (key: DeprecationTypes, instance) => boolean;
createCompatVue: (createApp, wrappedCreateApp) => CompatVue;
};Checks whether a specific compatibility feature is enabled for a component instance.
/**
* Check if a compatibility feature is enabled
* @param key - Deprecation type to check
* @param instance - Component instance (null for global)
* @param enableForBuiltIn - Enable for built-in components
* @returns True if the feature is enabled
*/
isCompatEnabled(key: DeprecationTypes, instance: Component | null, enableForBuiltIn?: boolean): boolean;Usage Example:
import { compatUtils, DeprecationTypes } from "vue";
// Check if global mount compatibility is enabled
if (compatUtils.isCompatEnabled(DeprecationTypes.GLOBAL_MOUNT, null)) {
// Use Vue 2 mounting syntax
new Vue(options).$mount('#app');
} else {
// Use Vue 3 mounting syntax
createApp(options).mount('#app');
}
// Check in component context
export default {
mounted() {
if (compatUtils.isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, this)) {
// Access $listeners
console.log(this.$listeners);
}
}
};Checks compatibility feature and throws error if disabled.
/**
* Check compatibility feature and throw error if disabled
* @param key - Deprecation type to check
* @param instance - Component instance
* @returns True if enabled, throws error if disabled
*/
checkCompatEnabled(key: DeprecationTypes, instance: Component | null): boolean;Soft assertion for compatibility features with warnings.
/**
* Soft assertion for compatibility features
* @param key - Deprecation type to check
* @param instance - Component instance
* @returns True if enabled, logs warning if disabled
*/
softAssertCompatEnabled(key: DeprecationTypes, instance: Component | null): boolean;Emit deprecation warnings for Vue 2 features being used.
/**
* Emit deprecation warning for Vue 2 features
* @param key - Deprecation type
* @param instance - Component instance
* @param args - Additional warning arguments
*/
warnDeprecation(key: DeprecationTypes, instance: Component | null, ...args: any[]): void;Usage Example:
import { compatUtils, DeprecationTypes } from "vue";
// Custom component using deprecated feature
export default {
methods: {
useDeprecatedFeature() {
// Warn about deprecated usage
compatUtils.warnDeprecation(
DeprecationTypes.INSTANCE_SET,
this,
'Using $set is deprecated. Use reactive assignment instead.'
);
// Still allow the deprecated functionality
this.$set(this.data, 'newProp', 'value');
}
}
};Creates a Vue 2-compatible constructor from Vue 3 createApp functions.
/**
* Create Vue 2-compatible constructor
* @param createApp - Vue 3 createApp function
* @param wrappedCreateApp - Wrapped createApp with compatibility
* @returns CompatVue constructor
*/
createCompatVue(createApp: Function, wrappedCreateApp: Function): CompatVue;Check compatibility before using features:
import { compatUtils, DeprecationTypes } from "vue";
export default {
mounted() {
// Pattern: Check before using deprecated feature
if (compatUtils.isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_EMITTER, this)) {
// Use Vue 2 event system
this.$on('custom-event', this.handleEvent);
} else {
// Use Vue 3 event system (emits)
this.$emit('custom-event', data);
}
},
methods: {
conditionalReactivity(obj, key, value) {
// Pattern: Conditional reactivity
if (compatUtils.isCompatEnabled(DeprecationTypes.GLOBAL_SET, null)) {
Vue.set(obj, key, value);
} else {
// Vue 3 reactivity is automatic
obj[key] = value;
}
}
}
};Create reusable migration helpers:
// migration-mixin.js
import { compatUtils, DeprecationTypes } from "vue";
export const migrationMixin = {
methods: {
safeSet(target, key, value) {
if (compatUtils.isCompatEnabled(DeprecationTypes.INSTANCE_SET, this)) {
this.$set(target, key, value);
} else {
target[key] = value;
}
},
safeDelete(target, key) {
if (compatUtils.isCompatEnabled(DeprecationTypes.INSTANCE_DELETE, this)) {
this.$delete(target, key);
} else {
delete target[key];
}
},
isVue2Mode() {
return compatUtils.isCompatEnabled(DeprecationTypes.GLOBAL_MOUNT, null);
}
}
};
// Use in components
export default {
mixins: [migrationMixin],
methods: {
updateData() {
// Use migration-safe methods
this.safeSet(this.user, 'newField', 'value');
}
}
};Gradually migrate components from Vue 2 to Vue 3 mode:
// Step 1: Start with Vue 2 compatibility
export default {
name: 'ComponentV1',
compatConfig: {
MODE: 2, // Full Vue 2 compatibility
},
data() {
return { count: 0 };
},
methods: {
increment() {
this.count++;
}
}
};
// Step 2: Migrate to hybrid mode
export default {
name: 'ComponentV2',
compatConfig: {
MODE: 3, // Vue 3 mode
INSTANCE_EVENT_EMITTER: true, // Keep some Vue 2 features
OPTIONS_DATA_FN: true
},
data() {
return { count: 0 };
},
setup() {
// Start using Composition API alongside Options API
const newFeature = ref('value');
return { newFeature };
}
};
// Step 3: Full Vue 3 migration
export default {
name: 'ComponentV3',
compatConfig: {
MODE: 3 // Pure Vue 3 mode
},
setup() {
// Full Composition API
const count = ref(0);
const increment = () => count.value++;
return { count, increment };
}
};Integrate compatibility checking with build tools:
// webpack plugin for migration analysis
class VueCompatAnalyzer {
apply(compiler) {
compiler.hooks.compilation.tap('VueCompatAnalyzer', (compilation) => {
// Analyze Vue compat usage during build
compilation.hooks.buildModule.tap('VueCompatAnalyzer', (module) => {
if (module.resource?.endsWith('.vue')) {
// Check for compatibility patterns
this.analyzeComponent(module);
}
});
});
}
analyzeComponent(module) {
// Custom analysis logic
const source = module._source?.source();
if (source?.includes('compatConfig')) {
console.log(`Component ${module.resource} uses compatibility config`);
}
}
}All available deprecation types for compatibility checking:
enum DeprecationTypes {
// Global API
GLOBAL_MOUNT = 'GLOBAL_MOUNT',
GLOBAL_EXTEND = 'GLOBAL_EXTEND',
GLOBAL_PROTOTYPE = 'GLOBAL_PROTOTYPE',
GLOBAL_SET = 'GLOBAL_SET',
GLOBAL_DELETE = 'GLOBAL_DELETE',
GLOBAL_OBSERVABLE = 'GLOBAL_OBSERVABLE',
// Instance API
INSTANCE_SET = 'INSTANCE_SET',
INSTANCE_DELETE = 'INSTANCE_DELETE',
INSTANCE_DESTROY = 'INSTANCE_DESTROY',
INSTANCE_EVENT_EMITTER = 'INSTANCE_EVENT_EMITTER',
INSTANCE_LISTENERS = 'INSTANCE_LISTENERS',
INSTANCE_CHILDREN = 'INSTANCE_CHILDREN',
// Component Options
OPTIONS_DATA_FN = 'OPTIONS_DATA_FN',
OPTIONS_BEFORE_DESTROY = 'OPTIONS_BEFORE_DESTROY',
OPTIONS_DESTROYED = 'OPTIONS_DESTROYED',
// And many more...
}type Component = ComponentOptions | ComponentPublicInstance;// Good: Check specific features
if (compatUtils.isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, this)) {
// Use $listeners
}
// Avoid: Mode-based detection
if (this.$compatMode === 2) {
// Less maintainable
}methods: {
safeEventHandler() {
// Gracefully handle different Vue versions
try {
if (compatUtils.isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_EMITTER, this)) {
this.$on('event', handler);
} else {
// Vue 3 approach
this.$emit('event', data);
}
} catch (error) {
console.warn('Event handling fallback:', error);
}
}
}// Track migration progress
const migrationStatus = {
component: 'MyComponent',
compatFeatures: [
'INSTANCE_LISTENERS',
'GLOBAL_EXTEND'
],
migrationPlan: [
'Remove $listeners usage',
'Replace Vue.extend with defineComponent'
]
};Install with Tessl CLI
npx tessl i tessl/npm-vue--compat