Ir al contenido

Adapter de Qwik

El adapter de Qwik es el de menor superficie y el más invasivo en comportamiento. Existe porque el modelo de resumabilidad de Qwik es fundamentalmente incompatible con el Shadow DOM de fábrica, y arreglarlo obliga a parchear document.addEventListener para toda la página.

Ventana de terminal
npm install wu-framework @builder.io/qwik
src/main.tsx
import { component$, useSignal } from '@builder.io/qwik';
import { wuQwik } from 'wu-framework/adapters/qwik';
const Counter = component$(() => {
const count = useSignal(0);
return (
<div>
<span>{count.value}</span>
<button onClick$={() => count.value++}>+</button>
</div>
);
});
wuQwik.register('counter', Counter);
Opción Tipo Por defecto Notas
props object {} Se pasan a qwik.jsx(Component, props) al montar.

Devuelve Promise<boolean>.

Esa es la tabla de opciones completa. No hay onMount, ni onUnmount, ni standalone, ni standaloneContainer.

Qwik no envía manejadores de eventos al navegador. Envía atributos QRLon:click, on:input— y un script diminuto llamado qwikloader que registra listeners en fase de captura sobre document. Cuando se dispara un evento, qwikloader lee event.target, sube buscando un atributo on:* que coincida y descarga de forma perezosa el chunk del manejador. Eso es la resumabilidad.

Dentro del Shadow DOM, esto se rompe. El navegador reapunta event.target al host del shadow para los listeners fuera del árbol, así que cuando qwikloader ve el evento, event.target es el elemento envoltorio, no el botón. En el host no hay atributos on:*. No pasa nada, en silencio.

Consulta QwikDev/qwik-evolution#283.

patchDocumentListenersForShadowDOM() reemplaza document.addEventListener y document.removeEventListener. Solo para manejadores de tipo función en fase de captura, instala un envoltorio que:

  1. lee event.composedPath(), que atraviesa los límites del shadow;
  2. si path[0] !== event.target —es decir, si realmente hubo reapuntado— le entrega al manejador un Proxy del evento cuyo target es el elemento real;
  3. si no, llama al manejador original con el evento intacto.

Por tanto los eventos del DOM ligero pasan con coste cero: nunca se construye ningún Proxy.

El parche se ejecuta una vez por página (guarda _patched) y permanece activo de forma permanente, porque qwikloader registra tipos de evento nuevos de forma perezosa conforme aparecen atributos on:* nuevos en el DOM. No se puede instalar por montaje y quitar al desmontar.

Una vez por documento (protegido por document.__wu_qwikloader), el adapter importa QWIK_LOADER de @builder.io/qwik/loader y lo añade como <script> inline a document.head. Si ese import falla, avisa y continúa: el renderizado sigue funcionando, la interactividad no.

El parche se instala antes del script de qwikloader, de modo que los propios manejadores en fase de captura de qwikloader quedan envueltos desde su primer registro.

// montaje
const vnode = qwik.jsx(Component, options.props || {});
renderResult = await qwik.render(container, vnode);
// desmontaje
renderResult.cleanup();
container.innerHTML = '';

Los errores de render se capturan y se pintan en el contenedor como un bloque <pre>, pasando antes el mensaje por escapeHtml(): el texto del error puede venir de un módulo remoto y no se puede confiar en él como markup. Consulta Escribir un adapter para ver por qué importa.

El ciclo de vida que se pasa a wu.define() es exactamente { mount, unmount }. wu.update('counter', …) no hace nada, y el markup de servidor se monta encima en lugar de reanudarse.

La resumabilidad propia de Qwik es un mecanismo distinto del slot hydrate de Wu: reanuda desde el estado serializado en el HTML en vez de volver a ejecutar un render de cliente. Unir ambos no es algo que este adapter intente.

Registrar una micro-app de Qwik cambia el estado global de la página. Conviene saberlo antes de añadir una a un shell:

Efecto Alcance ¿Se revierte al desmontar?
document.addEventListener parcheado todo el documento no — permanente
document.removeEventListener parcheado todo el documento no — permanente
<script> de qwikloader en <head> todo el documento no — una vez por documento
Flag document.__wu_qwikloader todo el documento no

Ninguno de estos se dispara salvo que se haya encontrado realmente una instancia de Wu.

import {
wuQwik, // export por defecto
register,
getWuInstance,
waitForWu,
} from 'wu-framework/adapters/qwik';

Desde el barrel: registerQwik.