Adapter de Vue
El adapter de Vue registra un componente raíz de Vue 3 como micro-app. Soporta props vivas e hidratación SSR, pero —a diferencia de React— ambas son condicionales a lo que exponga tu build de Vue, y el adapter solo anuncia el slot del ciclo de vida cuando la capacidad realmente está.
npm install wu-framework vue// src/main.ts — la micro-appimport { wuVue } from 'wu-framework/adapters/vue';import App from './App.vue';
wuVue.register('catalog', App);register(appName, RootComponent, options)
Sección titulada «register(appName, RootComponent, options)»import { createPinia } from 'pinia';import { router } from './router';
await wuVue.register('catalog', App, { props: { apiUrl: 'https://api.example.com' }, setup: (app) => { app.use(createPinia()); app.use(router); app.component('MoneyLabel', MoneyLabel); }, standaloneContainer: '#app', onMount: (container, app) => console.log('montado', app.version), onUnmount: (container, app) => console.log('desmontando'),});| Opción | Tipo | Por defecto | Notas |
|---|---|---|---|
props |
object |
{} |
Se pasan como props raíz. Se hacen reactivas cuando es posible — ver abajo. |
setup |
function |
null |
(app) => void. Se ejecuta después de createApp(), antes de mount(). Tu punto de enganche para plugins, router, componentes globales y directivas. |
standalone |
boolean |
true |
Monta directamente cuando no se encuentra un shell. |
standaloneContainer |
string |
'#app' |
Selector usado en modo standalone. Ojo: #app, no el #root de React. |
onMount |
function |
null |
(container, app) => void — recibe la instancia de la app Vue. |
onUnmount |
function |
null |
(container, app) => void — se ejecuta antes de app.unmount(). |
Devuelve Promise<boolean>.
setup es donde van los plugins
Sección titulada «setup es donde van los plugins»setup(app) es el único sitio donde instalar cualquier cosa a nivel de app. Se
ejecuta en cada montaje (y en cada hidratación), así que una micro-app reubicada
o remontada obtiene una aplicación Vue totalmente configurada, no una a medio
cablear.
El adapter también provee dos inyectables a todos los componentes del árbol:
<script setup>import { inject } from 'vue';
const appName = inject('wuAppName'); // 'catalog'const wu = inject('wuInstance'); // la instancia de Wu, o null</script>De dónde sale Vue
Sección titulada «De dónde sale Vue»ensureVue() comprueba primero window.Vue y luego recurre a un
import('vue') dinámico. Si ninguno resuelve, register() devuelve false.
Props vivas — condicionales a Vue.reactive
Sección titulada «Props vivas — condicionales a Vue.reactive»El adapter envuelve tus props en Vue.reactive() en el momento del registro,
y mutar ese objeto se propaga al componente raíz sin remontar:
await wu.update('catalog', { apiUrl: 'https://staging.example.com' });Si Vue.reactive no está disponible en el namespace de Vue resuelto, el
adapter usa un objeto plano y no anuncia update en absoluto. Ese es el
resultado honesto: asignar a un objeto plano no dispararía ninguna reactividad,
así que wu.update() parecería funcionar sin hacer nada. Sin el slot,
wu.update() no hace nada de forma visible.
Hidratación SSR — condicional a createSSRApp
Sección titulada «Hidratación SSR — condicional a createSSRApp»Cuando Vue 3 expone createSSRApp, el adapter anuncia hydrate. wu-core lo
llama en lugar de mount cuando el contenedor vino de wu-framework/server, y
createSSRApp(...).mount(container) adopta el DOM existente en vez de
recrearlo: sin parpadeo, y lo que el usuario ya está viendo se queda en
pantalla.
Las props del servidor se fusionan sobre las props reactivas antes de hidratar: son las props que produjeron el markup.
Si la hidratación lanza, el adapter lo registra y recurre a un mountApp()
normal. En Vue 2 (sin createSSRApp) el slot hydrate simplemente no está y el
markup del servidor se monta encima.
Shadow DOM y estilos de Vite
Sección titulada «Shadow DOM y estilos de Vite»Wu monta las micro-apps dentro del Shadow DOM por defecto, pero la inyección de
estilos de Vue en modo desarrollo escribe etiquetas
<style data-vite-dev-id> en document.head — fuera del límite del shadow,
donde no pueden alcanzar tus componentes.
Al montar, el adapter sube desde el contenedor buscando un ShadowRoot. Cuando
lo encuentra, espera unos 100 ms a que Vue inyecte sus estilos y luego clona
dentro del shadow root cada style[data-vite-dev-id] cuya ruta de id contenga
/<appName>/ (o \<appName>\ en Windows).
Lado del shell: WuSlot
Sección titulada «Lado del shell: WuSlot»Vue es el único adapter que exporta un componente listo para usar en lugar de una factoría:
<script setup>import { WuSlot } from 'wu-framework/adapters/vue';</script>
<template> <WuSlot name="catalog" url="http://localhost:3001" fallback-text="Cargando catálogo…" @load="onLoad" @error="onError" @mount="onMount" @unmount="onUnmount" /></template>| Prop | Tipo | Obligatoria | Notas |
|---|---|---|---|
name |
String |
sí | Nombre de la micro-app. |
url |
String |
sí | URL de la app. |
appName |
String |
no | Sustituye a name para la búsqueda en Wu. |
fallbackText |
String |
no | Por defecto 'Loading...'. |
Emite load, error, mount y unmount.
WuSlot usa una función de render, no un template, así que funciona con el
build runtime-only de Vue. Resuelve h() desde el namespace de Vue del adapter
o desde window.Vue; si ninguno está accesible, registra un error explícito en
lugar de renderizar null para siempre en silencio.
wuVuePlugin
Sección titulada «wuVuePlugin»import { createApp } from 'vue';import * as Vue from 'vue';import { wuVuePlugin } from 'wu-framework/adapters/vue';
const app = createApp(Shell);app.use(wuVuePlugin, { Vue }); // { Vue } es opcional — ver abajoapp.mount('#app');El plugin:
- registra
WuSlotglobalmente, - provee
wupara inyección, - añade
$wu,$wuEventsy$wuStore(ns)aglobalProperties, - envuelve
app.unmountpara que las suscripciones de$wuEventsse limpien.
Pasa { Vue } cuando 'vue' no sea un especificador simple resoluble en tu
build y no exista window.Vue: esa es la única forma de que
WuSlot.render() obtenga h().
Composables
Sección titulada «Composables»useWuEvents()
Sección titulada «useWuEvents()»<script setup>import { onUnmounted } from 'vue';import { useWuEvents } from 'wu-framework/adapters/vue';
const { emit, on, once, off, cleanup } = useWuEvents();
on('user:login', (e) => console.log(e.data));onUnmounted(cleanup);</script>useWuStore(namespace)
Sección titulada «useWuStore(namespace)»<script setup>import { onUnmounted } from 'vue';import { useWuStore } from 'wu-framework/adapters/vue';
const { state, setState, getState, cleanup } = useWuStore('user');onUnmounted(cleanup);</script>
<template> <p>{{ state.value?.name }}</p></template>state es un ref cuando Vue.ref está disponible, y un objeto plano
{ value: null } en caso contrario. setState(path, value) escribe en
<namespace>.<path>. Llama a cleanup() al desmontar.
IA: useWuAI y createUseWuAI(Vue)
Sección titulada «IA: useWuAI y createUseWuAI(Vue)»<script setup>import * as Vue from 'vue';import { createUseWuAI } from 'wu-framework/adapters/vue';
const useWuAI = createUseWuAI(Vue);const { messages, isStreaming, error, send, clear } = useWuAI({ namespace: 'support' });</script>createUseWuAI(Vue) devuelve un composable cuyos messages, isStreaming y
error son refs de Vue: reactivos en los templates. El export simple
useWuAI() no necesita el namespace de Vue pero devuelve valores no reactivos;
úsalo desde JavaScript normal, no desde un template.
Ambos llaman a wu.ai.send(). Vue no tiene variante de streaming: para salida
token a token, itera wu.ai.stream() tú mismo.
Exports
Sección titulada «Exports»import { wuVue, // export por defecto register, WuSlot, useWuEvents, useWuStore, wuVuePlugin, createUseWuAI, useWuAI, getWuInstance, waitForWu,} from 'wu-framework/adapters/vue';Desde el barrel, estos son registerVue, createVueUseWuAI y useVueWuAI.
