Saltar al contenido
Meeko
Escribe para buscar en las guías y en la referencia de la API. Ábrela desde cualquier página con / o Ctrl K; muévete con las flechas y entra con Intro.
Empezar
En esta página

Arquitectura de Meeko

Objetivo#

Meeko compila archivos .meeko a código TypeScript con renderWithState(props) o renderToString(props) para SSR y hydrate(root, props, state?) para conectar eventos y señales al DOM existente. El runtime del navegador evita un árbol virtual y actualiza los nodos afectados por cada señal.

Contrato actual#

  1. <script lang="ts"> declara tipos, imports y estado. defineProps<Props>() es una macro de compilación. En una página, <script server lang="ts"> declara las opciones de ruta; el compilador lo excluye del componente y Vite lo sirve como un módulo aparte (<página>.meeko?meeko-route&lang.ts), sólo en el servidor salvo en las rutas render: "client".
  2. <template> define HTML, expresiones de texto {expression}, eventos on:event="handler", atributos dinámicos bind:name="expression", condiciones if:when y listas each:of con claves obligatorias.
  3. <style> es opcional. scoped añade un atributo estable a los elementos y a los selectores CSS; con css.scopeAttribute: "matched", sólo a los elementos que esos selectores pueden seleccionar (véase Estilos con ámbito).
  4. El servidor escapa el texto dinámico e inserta marcadores para las expresiones reactivas.
  5. La aplicación transfiere props y estado de renderWithState al navegador como JSON escapado. Cada hijo anidado lleva su estado dentro de su marcador inicial. Durante hydrate, Meeko restaura señales, busca los marcadores, verifica el texto existente, conecta eventos y crea observadores. La función devuelta libera estos recursos.

El ejemplo de examples/counter ejercita el contrato en un servidor HTTP. Cada llamada a hydrate reclama una raíz de componente; varias llamadas sobre raíces independientes mantienen sus señales y eventos aislados. Los hijos importados usan hydrateScope en rangos de comentarios: esto permite anidarlos sin elementos envolventes y evita que sus marcadores se confundan con los del padre.

Límites de responsabilidad#

Parte Responsabilidad
Parser Analizar secciones, plantilla y expresiones conservando posiciones originales.
Compilador Validar la sintaxis y producir módulos tipados para SSR e hidratación.
Runtime reactivo Registrar dependencias, agrupar actualizaciones y liberar observadores por instancia.
Runtime de navegador Reclamar nodos existentes, conectar eventos y aplicar cambios precisos.
Integración de herramientas Mostrar diagnósticos en .meeko, transformar archivos en Vite y mantener HMR.
Framework Rutas, páginas, modos de render, navegación y clientes API/RPC/Socket (src/framework).
Núcleo de servidor Aplicación portable sobre Web APIs: runtime, contratos, sesiones, middleware y Socket (src/framework-server).
Adaptadores Conectar el núcleo con Node, Bun, Deno y Cloudflare Workers (src/node.ts, src/bun.ts, src/deno.ts, src/cloudflare.ts).

La guía del framework describe el framework, el servidor y los adaptadores.

El parser de secciones vive en src/compiler/parser/sfc.ts; src/compiler/parser/template.ts construye un AST propio de HTML. Ambos conservan límites de inicio y fin en el archivo original. El generador de src/compiler.ts usa esas posiciones para errores de sintaxis y devuelve segmentos de mapeo para el script y las expresiones. src/check.ts verifica el módulo mediante TypeScript 7 y presenta los errores en el .meeko original. Un error en código auxiliar generado sin segmento se identifica como tal y se sitúa al inicio del archivo para no atribuirle una ubicación falsa.

Compilador: expresiones, CSS y generación#

src/compiler.ts conserva la orquestación de SSR e hidratación y el contrato público compile. Dos pasos tienen módulos internos propios:

  • compiler/expressions.ts: validación de expresiones, nombres libres, condiciones de estrechamiento y reescritura de locales. Al reemplazar un parámetro de snippet o una fila de lista, conserva los segmentos originales con markSource; extraerlo no cambia el origen que recibe un diagnóstico.
  • compiler/transforms/scoped-css.ts: transformación de selectores, :global(...), exclusión de keyframes y cálculo de los elementos a los que se aplica el atributo de ámbito. Mantiene las ubicaciones de PostCSS para que el orquestador las traduzca al .meeko.

Estos módulos no son nuevas entradas públicas del paquete. Las pruebas de snippets, estrechamiento, estilos y mapeos comprueban el mismo comportamiento observable en los tres pasos.

app/runtime/client.ts coordina la aplicación, los layouts y la confirmación de la ruta. client-payload.ts valida el payload de hidratación y su versión antes de modificar el árbol. client-deferred.ts agrupa la validación de fragmentos deferred, su cola hasta que la página se haya montado, la lectura ndjson, los timeouts y la cancelación de los loaders del navegador.

La confirmación de DOM, head, estado compartido, layouts y token CSRF sigue siendo una operación del orquestador. Los helpers de transporte no pueden confirmar una ruta ni tocar el historial. View Transitions envuelve esa confirmación después de preparar módulos y datos; no envuelve la carga de la página. Las pruebas de streaming y navegación verifican que una ruta abortada no sobrescriba la nueva y que un fallo conserve la vista anterior.

Los límites de rendimiento y el escenario reproducible están descritos en Rendimiento.

El runtime de src/dom.ts usa comentarios como límites de condiciones, listas y componentes hijos. Una lista comprueba las claves durante SSR y al hidratar; al cambiar, mueve los rangos de nodos de las claves existentes. Cada elemento de la lista mantiene señales para su dato y su índice, de modo que expresiones reactivas y comparaciones estrictas leen los valores actuales. Al quitar una región se desconectan sus eventos y observadores.

<MeekoTeleport> (desde 1.5, src/teleport.ts) compila su contenido en la plantilla del componente, como el de una condición, y lo encierra entre <!--meeko:portal…--> y <!--/meeko:portal…-->. En un documento del servidor, renderTeleport entrega el contenido a un colector y deja en su sitio una referencia (<!--meeko:portal-ref:clave-->); src/framework/teleports.ts lo coloca después, sobre el HTML final, dentro del elemento del id o tras la aplicación, así que el destino puede renderizarse antes o después. Al hidratar, bindTeleport sigue la referencia hasta el contenido, lo hidrata en el componente que lo declara y mueve esos mismos nodos cuando cambian to o disabled. Las búsquedas de marcadores saltan los rangos meeko:portal, de modo que el contenido teleportado nunca se confunde con los marcadores del componente que contiene su destino. Sin colector (un render en el navegador o fuera del framework) el contenido sale en su sitio y el navegador lo mueve al terminar el montaje.

<component is> con una etiqueta HTML (desde 1.5) se compila según los resultados posibles de is, que el compilador lee de la sintaxis (src/compiler/transforms/dynamic-tag.ts): si todos son literales, es un elemento sin marcadores cuyos hijos pertenecen a la plantilla que lo rodea; si alguno puede ser un componente, el elemento va entre los comentarios del rango del componente y su contenido es el snippet default. src/dynamic-tag.ts comprueba la etiqueta antes de escribir HTML, en SSR y en el navegador, y tipa la unión de etiquetas, sus atributos y bind="obj"; src/html-attributes.ts copia los datos HTML de vscode-html-languageservice, de los que el compilador escribe junto a cada atributo no global la lista de etiquetas que lo admiten. Al cambiar la etiqueta, bindElementTag y bindDynamic crean el elemento nuevo, le mueven los hijos con sus nodos y vuelven a enlazar sólo los enlaces propios del elemento; los de los hijos siguen vivos. bindSpread escribe y retira los atributos de bind="obj".

El plugin src/vite.ts usa el mismo compilador para cliente y SSR y expone el CSS como módulo virtual. En desarrollo, cada componente acepta sus propias actualizaciones HMR: src/hmr.ts captura las señales editables por instancia, renderiza la nueva versión, hidrata su raíz o rango existente y actualiza los estilos. Una actualización del runtime recarga la página.

Los módulos generados importan el runtime desde @meekojs/meeko/internal. Esta ruta agrupa las funciones de DOM, SSR, HMR y DevTools que el compilador necesita y se versiona junto con él. Desde 1.5, un componente que usa <MeekoThemeToggle>, <MeekoAwait>, <MeekoPopover> o <MeekoSelect> importa además su módulo compilado (@meekojs/meeko/builtins/theme-toggle, /await, /popover o /select), y sólo ese componente: la tabla builtinComponentModules del compilador asocia cada etiqueta a su módulo, y scripts/builtin-components.ts compila su .meeko dentro del paquete. Una etiqueta integrada nueva sigue ese patrón para no crecer el runtime de todas las aplicaciones. En desarrollo, src/devtools.ts registra las instancias hidratadas y expone un hook de lectura que comparten el panel integrado y la extensión de Chrome. Ni SSR ni el build de producción registran instancias en ese hook.

Desde core 1.8, <MeekoPopover>, <MeekoSelect> y <MeekoThemeToggle> están obsoletos: el compilador emite MEEK121 y el editor tacha la etiqueta y explica el reemplazo en el hover. Siguen funcionando en 1.x y se retiran en 2.0. Usa UIPopover, UISelect y UIThemeToggle del módulo @meekojs/ui 0.2; el sistema de temas permanece en core. Véase Migración a 1.8.

Reglas para SSR#

  • Cada petición debe crear su propio estado. No se comparten señales con datos de usuarios entre peticiones.
  • El HTML dinámico se escapa antes de insertarse. El JSON inicial se escapa para no cerrar su etiqueta <script>.
  • Las expresiones que afectan el HTML inicial deben producir el mismo valor en servidor y navegador; renderWithState transfiere las señales editables cuando su valor inicial no es determinista. Una diferencia es un error de hidratación.
  • Los IDs de marcadores son locales a cada componente y se buscan sólo dentro de su raíz o rango de comentarios.
  • Las listas exigen claves estables para conservar nodos y estado al reordenarse.

TypeScript#

El proyecto utiliza TypeScript 7.0.2 estable para la compilación y la verificación de tipos. El parser de scripts usa temporalmente @typescript/typescript6, aislado como dependencia del compilador, porque TypeScript 7.0 no expone una API programática estable. El módulo generado se comprueba con TypeScript 7. meeko types emite declaraciones .d.meeko.ts para que un consumidor con allowArbitraryExtensions compruebe imports y props. El servidor de lenguaje de src/language-server usa los mapeos de origen y un documento TypeScript virtual para ofrecer diagnósticos y operaciones semánticas sobre .meeko. Lo usan la extensión de VS Code y otros editores.

Límite entre runtime y herramientas#

El bundle del navegador sólo incorpora los módulos usados por la aplicación; las mediciones registran su tamaño comprimido por separado. La instalación de @meekojs/meeko sí incluye el compilador, TypeScript 7, el analizador TypeScript 6, parse5 y PostCSS porque la CLI y el plugin Vite pertenecen al mismo paquete. El coste de instalación y el tamaño del JS servido son métricas distintas.

En la serie 1.x Meeko se publica como un único paquete. El código generado y @meekojs/meeko/internal deben tener exactamente la misma versión, y meeko init fija esa versión exacta en los proyectos que crea. Separar compilador y runtime añadiría una segunda versión que coordinar en cada build, sin un beneficio medido que lo justifique. La política de estabilidad recoge esta decisión. Si en el futuro el coste de instalación aconsejara dividir el paquete, la división conservaría una ruta de compatibilidad para los módulos .meeko ya compilados y tendría pruebas de consumo desde paquetes publicados.

¿Te sirvió esta página?

Añadir un comentario

Se envía al elegir «Sí» o «No». Solo se guardan la página, tu respuesta y el comentario: ni cookies ni datos tuyos.

0 de 2000 caracteres

Editar en GitHub: docs/architecture.md