@firecoder-com/vite-plugin-vue-oop v1.0.1
@firecoder-com/vite-plugin-vue-oop
This package performs a live-patching (or monkey patching) of @vitejs/plugin-vue to enable Vue class components to make use of inheritance and Object oriented Programming(OOP).
Usage
Import this package in your vite.config.ts
file like this:
import { defineConfig } from "vite";
import vue from "@firecoder-com/vite-plugin-vue-oop";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
// ... more plugins ...
],
// ... configuration ...
});
Configuration
This plugin makes use of the original plugin and just live-patches the return value of the plugin. So, for configuration options see: @vitejs/plugin-vue.
Motivation
The original plugin removes the class from
the export and only returns its __vccOpts
property (a.k.a. "Vue class component options"). This does not work well
with Vue class components implemented by a class hierarchy as no class to inherit from is eported.
As it is seems to be a deliberate decision by the developers of the original plugin to do so, this
monkey patching replacement was created. Because the reasoning behind
stripping the class and returning only __vccOpts
by the vite build system is unknown, this seems better than
submitting a patch and risking unanticipated side effects. Now, any user of Vite and Vue is able to decide, whether to
use this plugin or use the original one.
However, Vue would handle classes and inheritance deliberately (see: runtime-core #isClassComponent).
Use case - Oject oriented programming
---------------
| ButtonBase |
---------------
|
__________________^____________________
| | |
------------- ------------- -------------
| Button1 | | Button2 | | Button3 |
------------- ------------- -------------
A base component implements the common behaviour of a menu buttons system, where all buttons look the same and behave
the same. Nevertheless, the icons, the descriptions and the actions, performed on button press, differ.
With the original @vitejs/plugin-vue
, you need to copy the template and all the code to every button component as
there is no possibility to create a class hierarchy with components.
This plugin makes it possible to create a base component - even with a template. All buttons only need to overwrite the action, the icon and the description. Implementing a menu with 20 buttons decreases the code dramatically.
I guess there is no need to talk about the benefits of OOP?
Vue class component
Although not widely known, there is a way to use classes with Vue 3 as
Vue knows "Vue Class components" (see:
Vue 3 package runtime-core
).
A class need to export a static member called __vccOpts
containing a factory function
named setup()
. This is the very same function from the
Vue 3 composition API.
If a component of that class is created, its factory function is called to create the instance.
See this example on SFC Playground:
File HelloWorld.vue
<template>
<h1>{{ message }}</h1>
</template>
<script lang="ts">
import { ref } from "vue";
import type { ComponentOptions } from "vue";
export default class MessageTextAsClass {
public message = ref("Hello World!");
static setup(props: Readonly<Record<string, unknown>>): MessageTextAsClass {
const instance = new MessageTextAsClass();
// apply all provided properties
if (props) {
Object.getOwnPropertyNames(props)
.forEach((propName) => Object.defineProperty(instance, propName, {
get() {
return props[propName];
},
}))
;
}
return instance;
}
// this is the flag that makes the class work with Vue 3.
static __vccOpts: ComponentOptions = {
setup: MessageTextAsClass.setup,
get render() {
return (MessageTextAsClass as { render: (() => unknown)}).render;
},
set render(renderFunc: () => void) {
(MessageTextAsClass as { render: (() => unknown)}).render = renderFunc;
},
};
}
</script>
File App.vue
<script setup>
import HelloWorld from "./HelloWorld.vue";
</script>
<template>
<HelloWorld/>
<input v-model="msg">
</template>