1.0.1 • Published 1 year ago

@firecoder-com/vite-plugin-vue-oop v1.0.1

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

@firecoder-com/vite-plugin-vue-oop

License: MIT

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>

License

MIT

1.0.1

1 year ago

1.0.0

1 year ago