How to Build a Mini TinyVue Component Library for Vue 2 & 3
Learn how to create a mini version of the TinyVue component library that works across Vue 2.6, Vue 2.7, and Vue 3 by using a single source code strategy, adaptive layers, renderless logic, and unified APIs, with practical code examples and migration solutions.
Why implement a component library across frameworks?
Vue has two major branches, Vue 2 and Vue 3, which are not compatible. Vue 2.7 serves as a bridge between 2.6 and Vue 3. Migrating projects incurs cost and risk, and existing component libraries provide separate versions for each framework.
TinyVue aims to support Vue 2.6, Vue 2.7, and Vue 3 with a single‑source‑code strategy and intelligent compilation, reducing maintenance cost and migration risk.
Key Technical Analysis
Using a button component as an example, the template integrates an adapter layer, renderless logic, and theme styles. All logic is extracted to a renderless function.
Flow: the Vue file imports the setup function and the renderless function from the adapter layer; the setup function constructs an object that smooths framework differences and passes it to renderless; renderless creates state and API, returns them to the adapter, which binds state to template data and API to events.
How to Resolve Framework Differences
1. Differences between frameworks
Template syntax differences
Lifecycle name changes
Removal of event modifiers, filters, message subscriptions
v-model syntax sugar differences
Directive and animation component differences
2. Internal runtime differences
Component instance differences
VNode structure differences
Removal of $children, $scopedSlots, etc.
Solution for reactive function imports
Expose a hooks variable in the adapter layer to unify reactive function access.
import { reactive, ref, watch, ... } from '@vue/composition-api' // Vue 2.6
import { reactive, ref, watch, ... } from 'vue' // Vue 3
// adapter/index.js
export { hooks }Solution for VNode and h function differences
Provide a unified h function in the adapter layer.
// adapter/vue2/index.js
import * as hooks from '@vue/composition-api'
const h = hooks.h
// adapter/vue3/index.js
const h = (component, propsData, childData) => {
// omitted code
let props = {}
let children = childData
if (propsData && typeof propsData === 'object' && !Array.isArray(propsData)) {
props = parseProps(propsData)
propsData.scopedSlots && (children = propsData.scopedSlots)
} else if (typeof propsData === 'string' || Array.isArray(propsData)) {
childData = propsData
}
return hooks.h(component, props, children)
}
// adapter/index.js
export { h }Solution for v-model differences
Define a model option in Vue 2 to customize the bound prop and event.
defineComponent({
model: {
prop: 'modelValue',
event: 'update:modelValue'
},
props: {
modelValue: String
}
})Solution for slots differences
Unify slot access by exposing $slots that works for both frameworks.
// adapter/vue2/index.js
Object.defineProperties(vm, {
$slots: { get: () => instance.proxy.$scopedSlots },
$scopedSlots: { get: () => instance.proxy.$scopedSlots }
})
// adapter/vue3/index.js
Object.defineProperties(vm, {
$slots: { get: () => instance.slots },
$scopedSlots: { get: () => instance.slots }
})Solution for directive lifecycle differences
Implement directive objects that support both Vue 2 and Vue 3 lifecycle names, keeping the parameters unchanged.
Solution for animation class differences
Define animation class names that work for both Vue 2 and Vue 3 transition components.
.fade-in-linear-enter,
.fade-in-linear-enter-from,
.fade-in-linear-leave-to {
opacity: 0;
}Overall, the team adopted two core principles: “seek commonality, eliminate differences” by using syntax supported by both frameworks, and “compatibility and inclusion” by building an adapter layer that hides framework differences, allowing developers to focus on business logic.
Huawei Cloud Developer Alliance
The Huawei Cloud Developer Alliance creates a tech sharing platform for developers and partners, gathering Huawei Cloud product knowledge, event updates, expert talks, and more. Together we continuously innovate to build the cloud foundation of an intelligent world.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
