Adapters de framework
Un adapter es una capa fina de traducción. Wu Framework solo entiende un
contrato — wu.define(name, { mount, unmount, update?, hydrate? }) — y el
trabajo de cada adapter es expresar la semántica de montar/desmontar de tu
framework en esos términos, más un poco de plomería que de otro modo
escribirías a mano: esperar al shell, caer a modo standalone y llevar la
contabilidad de las props vivas.
Nunca necesitas un adapter. wu.define() funciona con cualquier framework.
El adapter existe para que no escribas las mismas 60 líneas en cada micro-app.
Los 13 adapters
Sección titulada «Los 13 adapters»| Adapter | Subpath | 2.º argumento de register() |
Props vivas (update) |
SSR (hydrate) |
Standalone | Contenedor por defecto |
|---|---|---|---|---|---|---|
| React | wu-framework/adapters/react |
Component | sí | sí | sí | #root |
| Vue | wu-framework/adapters/vue |
RootComponent | sí¹ | sí² | sí | #app |
| Angular | wu-framework/adapters/angular |
AppModule / Component | no | no | sí | #root |
| Svelte | wu-framework/adapters/svelte |
Component | sí³ | no | sí | #app |
| Preact | wu-framework/adapters/preact |
Component | sí⁴ | no | sí | #app |
| Solid | wu-framework/adapters/solid |
Component | no | no | sí | #root |
| Lit | wu-framework/adapters/lit |
ElementClass | sí | no | sí | #root |
| Vanilla | wu-framework/adapters/vanilla |
objeto config |
sí | no | sí | #app |
| Alpine | wu-framework/adapters/alpine |
objeto appConfig |
no | no | sí | #app |
| Qwik | wu-framework/adapters/qwik |
Component | no | no | no | — |
| Stencil | wu-framework/adapters/stencil |
string tagName |
no | no | sí | #app |
| HTMX | wu-framework/adapters/htmx |
objeto config |
no | no | sí | #app |
| Stimulus | wu-framework/adapters/stimulus |
objeto config |
no | no | sí | #app |
¹ Solo cuando Vue.reactive está disponible.
² Solo cuando Vue.createSSRApp está disponible (Vue 3).
³ Solo en register() — registerSvelte5() no anuncia update.
⁴ Solo en register() — registerCompat() no anuncia update.
Cómo elegir un adapter
Sección titulada «Cómo elegir un adapter»La decisión casi siempre es “el que se llama como tu framework”. Los casos interesantes son los solapamientos:
- Preact: usa
register()para una app Preact nativa. UsaregisterCompat()solo si el árbol de componentes se escribió contra la API de React e importa depreact/compat. - Svelte:
register()para Svelte 3/4 (new Component({ target })),registerSvelte5()para Svelte 5 (mount()del paquetesvelte). - Angular:
registerStandalone()es el punto de entrada recomendado.register()usaplatformBrowserDynamic+bootstrapModule, que llama adocument.querySelectorinternamente y por tanto no funciona dentro del Shadow DOM — el modo de aislamiento por defecto de Wu. - Lit vs Stencil: ambos producen custom elements. Usa el adapter de Lit
cuando escribes la clase tú mismo (llama a
customElements.definepor ti); usa el adapter de Stencil cuando el compilador de Stencil ya definió la etiqueta y solo necesitas que Wu la coloque. - Vanilla: no es un plan B. Tiene la superficie más rica de los adapters
ligeros (
register,registerClass,registerTemplate,createComponent) y es el único construido sobre el contrato compartidocreateWuAdapter().
El patrón de registro compartido
Sección titulada «El patrón de registro compartido»Todos los adapters exponen la misma forma: un objeto wuX exportado por
defecto, más exports nombrados para tree-shaking.
// Ambas formas funcionan; el import nombrado hace mejor tree-shaking.import { wuReact } from 'wu-framework/adapters/react';import { register } from 'wu-framework/adapters/react';
await wuReact.register('cart', CartApp, { props: { currency: 'EUR' }, standalone: true, standaloneContainer: '#root', onMount: (container) => console.log('montado en', container), onUnmount: (container) => console.log('saliendo de', container),});register() siempre es async y siempre resuelve a un boolean:
true— registrado con el shell, o montado en modo standalone.false— no se pudo cargar el framework, o Wu no estaba y el modo standalone estaba desactivado o faltaba su contenedor.
Las opciones de arriba (props, standalone, standaloneContainer,
onMount, onUnmount) son universales. Todo lo demás es propio de cada
adapter y está documentado en su página.
Modo standalone
Sección titulada «Modo standalone»Todos los adapters excepto Qwik implementan el mismo plan B. register() llama
a waitForWu(3000); si no aparece ninguna instancia wu en tres segundos y
standalone !== false, el adapter monta tu componente directamente en
document.querySelector(standaloneContainer) — sin Shadow DOM y sin el bus
de eventos.
Esto es lo que permite que un mismo bundle sirva para dos propósitos: ejecuta
npm run dev y obtienes una app normal en localhost:3001; carga la misma URL
desde un shell y obtienes un micro-frontend. Sin flags de build, sin un segundo
punto de entrada.
Pon standalone: false cuando una micro-app no tenga sentido por sí sola (por
ejemplo, si lee todo de wu.store) — así obtienes un false claro en lugar de
una página rota.
El barrel y loadAdapter()
Sección titulada «El barrel y loadAdapter()»import { loadAdapter, ADAPTER_NAMES } from 'wu-framework/adapters';
const wuReact = await loadAdapter('react');wuReact.register('cart', CartApp);
console.log(ADAPTER_NAMES);// ['react','vue','angular','svelte','preact','solid','lit',// 'vanilla','alpine','qwik','stencil','htmx','stimulus']loadAdapter(name) importa dinámicamente un adapter y resuelve a su objeto
wuX. Los resultados se cachean, y las llamadas concurrentes con el mismo
nombre comparten una única promesa en vuelo en lugar de competir con dos
llamadas a import(). Un nombre desconocido se rechaza con un mensaje que
lista los válidos. ADAPTER_NAMES es un array congelado, útil para iterar
desde herramientas.
Utilidades compartidas
Sección titulada «Utilidades compartidas»Cada adapter exporta dos helpers, que también están en
wu-framework/adapters/shared:
import { getWuInstance, waitForWu } from 'wu-framework/adapters/shared';
const wu = getWuInstance(); // window.wu → parent.wu → top.wu, o nullconst ready = await waitForWu(5000); // resuelve cuando aparece wu, si no rechazagetWuInstance() recorre window, luego window.parent y luego window.top,
protegiendo cada lectura cross-origin con un try: leer .wu en un Window
cross-origin lanza un SecurityError síncrono, y el encadenamiento opcional no
ayuda porque window.parent siempre es un Window.
waitForWu(timeout) escucha los eventos wu:ready y wu:app:ready y consulta
cada 200 ms como respaldo. Los adapters lo llaman con 3000; el valor por
defecto exportado es 5000.
Consulta Escribir un adapter para createWuAdapter(),
escapeHtml() y el contrato completo si quieres dar soporte a un framework que
no está en esta lista.
