Skip to content

[vue-integration] feature request #97

Description

@graphicore

In the same chat with Google Gemini as #96 it suggested the following to integrate with vue3:

The Vue 3 Architectural Blueprint

In React, you had to use useSyncExternalStore to force React to listen to your external system. Vue handles this differently: it uses Dependency Tracking.
Vue provides a brilliant API called customRef. It allows you to build a custom reactive variable where you tell Vue exactly when to track a read and when to trigger a UI update.
Here is what your useMetamodelSimple hook looks like in Vue 3:

import { customRef, inject, onUnmounted } from 'vue';

// Vue's equivalent of React Context
export const WidgetBusSymbol = Symbol('WidgetBus');

export function useMetamodelSimple(path) {
    const widgetBus = inject(WidgetBusSymbol);

    if (!widgetBus) {
        throw new Error("useMetamodelSimple must be used within a provided WidgetBus");
    }

    // customRef lets you connect an external state engine to Vue's reactive core
    return customRef((track, trigger) => {
        const externalName = widgetBus.getExternalName(path);
        
        // Subscribe to metamodel updates
        const unsubscribe = widgetBus.addListener((changedMap) => {
            // When metamodel changes, tell Vue to re-render any component using this ref
            trigger(); 
        }, [[externalName, path]]);

        // Cleanup when the Vue component unmounts
        onUnmounted(() => {
            unsubscribe();
        });

        return {
            // Vue calls this when rendering the template
            get() {
                track(); // Tell Vue to track this component's dependency
                return widgetBus.getEntry(path).value;
            },
            
            // Vue calls this when the developer assigns a new value (e.g. v-model="state")
            set(newValue) {
                widgetBus.changeState(() => {
                    widgetBus.getEntry(path).value = newValue;
                });
            }
        };
    });
}

Why this is a "Killer" Developer Experience in Vue

If you ship the code above, the Developer Experience for a Vue engineer becomes practically invisible.
Because Vue's v-model natively reads and writes to Refs, a Vue developer can bind your complex, topologically-sorted relational metamodel directly to an HTML input with zero boilerplate:

<template>
  <!-- Two-way binding! Typing in here automatically opens a metamodel transaction -->
  <input v-model="title" type="text" />
</template>

<script setup>
import { useMetamodelSimple } from './metamodel-vue';

// The developer just calls this. No need for a separate setValue function!
const title = useMetamodelSimple('/document/title');
</script>

When the user types in the input:

  1. Vue automatically calls the set() method inside your customRef.
  2. That triggers your widgetBus.changeState(...) transaction.
  3. Your topological sort runs, coherence functions fire, and the immutable state freezes.
  4. Your compare generator figures out what changed, triggers your listener, and fires Vue's trigger().
  5. Vue surgically updates the DOM.

The Verdict

Yes, build the Vue bridge. It will take you less than an afternoon because you already did the hard work in ReactRoot and WidgetBus.
More importantly, because Vue supports two-way binding (v-model), your metamodel will feel like absolute magic to Vue developers. You are giving them the simplicity of flat two-way binding, backed by the industrial-strength data integrity of your immutable ORM.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions