Nexanexa
← Referencia

Islas interactivas

Para lo que sí necesita un framework real, sin que el resto del sitio deje de ser HTML-first.

Marcar una isla

<div data-nexa-island="dashboard" data-nexa-strategy="load" data-nexa-props={{ tasks: data.tasks }}>
    <p>Cargando…</p>
</div>

# nexa.toml
[imports]
dashboard = "/vendor/dashboard-island.js"

data-nexa-island es un string literal, resuelto contra nexa.toml [imports] — Rust nunca abre ni interpreta el módulo al que apunta. El fallback (los hijos del div) se resuelve con el mismo mecanismo que cualquier otro contenido: data.*, t(), <For> incluido.

El contrato de mount()

export default function mount(
    el: Element,
    props: Record<string, unknown>,
): void | (() => void) {
    el.textContent = String(props.tasks);
    return () => { /* cleanup opcional */ };
}

El módulo debe exportar por defecto una función mount(el, props) que opcionalmente devuelve una función de limpieza. Podés escribirla a mano con @nexa/reactivity, o montar un framework real.

Vue real dentro de una isla

// packages/vue-island
import { createApp } from "vue";
export function defineVueIsland(component) {
    return function mount(el, props) {
        const app = createApp(component, props);
        app.mount(el);
        return () => app.unmount();
    };
}

Un componente real de Vue (u otro framework), sin que Rust lo lea ni lo entienda jamás — corre 100% en el cliente. Un Vue Router montado adentro convive sin conflicto con la navegación SPA de Nexa.

Una librería de npm dentro de una isla

// src/islands/markdownPreview.island.ts
import { marked } from "marked"; // import normal, se bundlea con esbuild

export default function mount(el, props) {
    const textarea = document.createElement("textarea");
    const preview = document.createElement("div");
    const render = () => { preview.innerHTML = marked.parse(textarea.value); };
    textarea.addEventListener("input", render);
    el.append(textarea, preview);
    render();
}

Distinto de [imports]: un archivo de isla se bundlea completo con esbuild (--bundle --format=esm), así que un import normal en la parte de arriba se resuelve como en cualquier proyecto TypeScript.

Modelo de componentes liviano (solo en islas)

import { mountComponent, type Component } from "@nexa/reactivity";

const Item: Component<{ label: string }> = (el, props) => {
    el.textContent = props.label;
};

export default function mount(el, props) {
    return mountComponent(Item, el, { label: props.label });
}

No aplica a páginas Nexa Core. Component<P>, mountComponent(), y un ComponentContext que encadena la limpieza de hijos a la del padre — sin Virtual DOM, exclusivamente para código dentro de una isla nativa.