Ir al contenido

Adapters de Solid y Preact

Solid y Preact hablan JSX y ambos son pequeños. Difieren en lo único que le importa a un adapter: cómo ocurre un re-render.

Preact hace diffing de un DOM virtual, así que volver a llamar a render() con props nuevas actualiza en el sitio: eso es un canal de props vivas. Solid compila la reactividad dentro del componente en tiempo de build; render() se ejecuta una vez y devuelve una función dispose, así que no existe un “renderiza otra vez con props nuevas”. Por eso Solid no anuncia update.

Preact Solid
Subpath wu-framework/adapters/preact wu-framework/adapters/solid
2.º argumento Component Component
Props vivas (solo register) no
Hidratación SSR no no
Contenedor standalone #app #root
Punto de entrada extra registerCompat()

Ventana de terminal
npm install wu-framework preact
src/main.jsx
import { wuPreact } from 'wu-framework/adapters/preact';
import App from './App';
wuPreact.register('widgets', App);
Opción Tipo Por defecto
props object {}
standalone boolean true
standaloneContainer string '#app'
onMount function null
onUnmount function null

Devuelve Promise<boolean>. ensurePreact() resuelve Preact desde el ámbito global o con un import dinámico; si falla, devuelve false.

Se inyectan dos props en tu componente además de las tuyas:

function App({ apiUrl, wuAppName, wuInstance }) {
return <h1>{wuAppName}{apiUrl}</h1>;
}
await wu.update('widgets', { apiUrl: 'https://staging.example.com' });

El adapter fusiona las props nuevas y llama a render() sobre el mismo contenedor. El diff de Preact actualiza el DOM existente: sin desmontar, sin perder estado.

Para árboles escritos contra la API de React y que corren sobre preact/compat:

import { wuPreact } from 'wu-framework/adapters/preact';
import App from './App'; // componente al estilo React
wuPreact.registerCompat('widgets', App);

Importa dinámicamente preact/compat y usa su render y createElement. Si preact/compat no está instalado, registra un error y delega en register() con los mismos argumentos, de modo que obtienes una app que funciona en lugar de un fallo.

La factoría de Preact toma dos argumentos: la función h y un objeto de hooks explícito.

import { h } from 'preact';
import { useState, useEffect, useRef } from 'preact/hooks';
import { createWuSlot } from 'wu-framework/adapters/preact';
const WuSlot = createWuSlot(h, { useState, useEffect, useRef });
function Shell() {
return (
<div>
<WuSlot name="widgets" url="http://localhost:3001" />
</div>
);
}

Compáralo con React, donde createWuSlot(React) recibe el namespace completo: React expone sus hooks en ese namespace, Preact no.

createUseWuEvents(hooks) y createUseWuStore(hooks)

Sección titulada «createUseWuEvents(hooks) y createUseWuStore(hooks)»

Mismo patrón: pasa los hooks que importes.

import * as hooks from 'preact/hooks';
import { createUseWuEvents, createUseWuStore } from 'wu-framework/adapters/preact';
const useWuEvents = createUseWuEvents(hooks);
const useWuStore = createUseWuStore(hooks);
function Cart() {
const { emit, on } = useWuEvents();
const { state, setState } = useWuStore('user');
// …
}
const useWuAI = createUseWuAI(hooks); // necesita { useState, useCallback }
function Assistant() {
const { messages, isStreaming, error, send, clear } = useWuAI({ namespace: 'support' });
// …
}

Sin streaming: espera a wu.ai.send() y añade la respuesta completa.

import {
wuPreact, // export por defecto
register,
registerCompat,
createWuSlot,
createUseWuEvents,
createUseWuStore,
createUseWuAI,
getWuInstance,
waitForWu,
} from 'wu-framework/adapters/preact';

Ventana de terminal
npm install wu-framework solid-js
src/index.jsx
import { wuSolid } from 'wu-framework/adapters/solid';
import App from './App';
wuSolid.register('reports', App);
Opción Tipo Por defecto
props object {}
standalone boolean true
standaloneContainer string '#root'
onMount function null
onUnmount function null

Devuelve Promise<boolean>. ensureSolid() carga solid-js y solid-js/web; si falla, devuelve false.

El adapter llama a render(() => Component({ ...props, wuAppName, wuInstance }), container) y guarda la función dispose devuelta para el desmontaje.

Devuelve una tupla [getter, setter], la convención de Solid:

import { createWuStore } from 'wu-framework/adapters/solid';
function Profile() {
const [user, setUser] = createWuStore('user');
return (
<div>
<p>{user()?.name}</p>
<button onClick={() => setUser('name', 'John')}>Poner nombre</button>
</div>
);
}

user es una señal: hay que llamarla. setUser(path, value) escribe en <namespace>.<path> del store de Wu. La suscripción a Wu se libera mediante onCleanup, así que debe llamarse dentro de un componente o de una raíz.

import { Show } from 'solid-js';
import { createWuEvent } from 'wu-framework/adapters/solid';
function Ticker() {
const lastUserEvent = createWuEvent('user:*');
return (
<Show when={lastUserEvent()}>
<p>Último evento: {lastUserEvent()?.name}</p>
</Show>
);
}

Una señal con el último evento coincidente, desuscrita vía onCleanup.

import { onMount } from 'solid-js';
import { useWuEvents } from 'wu-framework/adapters/solid';
function Cart() {
const { emit, on } = useWuEvents();
onMount(() => on('user:login', (e) => console.log(e.data)));
return <button onClick={() => emit('user:logout', { reason: 'manual' })}>Salir</button>;
}
import { createWuContext } from 'wu-framework/adapters/solid';
const { WuProvider, useWu, WuContext } = createWuContext();
function App() {
return <WuProvider><Inner /></WuProvider>;
}
function Inner() {
const wu = useWu(); // recurre a getWuInstance() fuera del provider
// …
}

No toma argumentos: las primitivas de Solid se resuelven internamente.

import { createWuSlot } from 'wu-framework/adapters/solid';
const WuSlot = createWuSlot();
function Shell() {
return (
<div>
<WuSlot name="header" url="http://localhost:3001" />
<WuSlot name="content" url="http://localhost:3002" />
</div>
);
}

createWuSlot() arranca ensureSolid() y devuelve de inmediato. Si Solid no ha terminado de cargar cuando el shell renderiza —lo más probable, ya que los shells renderizan de forma síncrona justo después—, el slot se degrada a una versión simple que sigue montando la micro-app, solo que sin primitivas reactivas. Lanzar un error abortaría el render completo del shell.

import { createUseWuAI } from 'wu-framework/adapters/solid';
const useWuAI = createUseWuAI();
function Assistant() {
const ai = useWuAI({ namespace: 'support' });
return (
<>
<For each={ai.messages()}>{(m) => <p>{m.content}</p>}</For>
<button onClick={() => ai.send('Hola')} disabled={ai.isStreaming()}>Preguntar</button>
</>
);
}
import {
wuSolid, // export por defecto
register,
createWuSlot,
createWuStore,
createWuEvent,
useWuEvents,
createWuContext,
createUseWuAI,
getWuInstance,
waitForWu,
} from 'wu-framework/adapters/solid';

Desde el barrel: registerSolid, createSolidWuSlot, createSolidWuStore, useSolidWuEvents, createSolidUseWuAI.