Nexanexa

Referencia de Nexa

Cada cosa que tiene Nexa, organizada como un catálogo — igual que la referencia de componentes de otros frameworks. Buscá por nombre o filtrá por categoría; cada card lleva al ejemplo real y funcional.

Núcleo y páginas

Rutas por archivo

Cada .tsx bajo src/pages/ es una ruta real. [slug].tsx captura un segmento dinámico; [locale] es el segmento especial que activa i18n en toda la rama.

Núcleo y páginas

Una página, de arriba a abajo

load/paths/seo/schema son objetos/plantillas literales — nunca se ejecutan, nexa-parser los reconoce como patrones y los resuelve él mismo contra datos reales en build/request. Por eso no pueden tener lógica: sin condicionales, sin .map(), sin funciones propias.

Núcleo y páginas

load() — traer datos

Un GET HTTP real contra NEXA_API_URL + url, con :params sustituidos por los valores reales de la ruta. El backend puede ser cualquier lenguaje — Nexa solo espera JSON de vuelta.

Núcleo y páginas

paths() — pre-renderizar rutas dinámicas

Misma forma que load, pero el backend responde con un array de sets de parámetros. nexa build genera un index.html real por cada entrada — HTML puro, sin depender de que el backend siga corriendo.

Núcleo y páginas

<For> — iterar listas

No es un componente ni un elemento HTML — es un patrón sintáctico fijo, igual que t("clave"). Rust clasifica el cuerpo del callback una sola vez (es una plantilla) y lo renderiza como HTML real una vez por elemento.

Núcleo y páginas

Link activo automático

Un <a href> cuyo href coincide con la ruta actual recibe aria-current="page" solo — sin escribir ningún condicional (una página Nexa no admite lógica propia). data-nexa-match="prefix" lo vuelve por prefijo, con límite de segmento.

Núcleo y páginas

Layouts compartidos

src/layout.tsx, opcional, envuelve el HTML de toda página del proyecto. Se compila igual que cualquier página — no es composición: nexa-cli busca el único data-nexa-slot vacío y ahí inserta, tal cual, el HTML ya renderizado de la página.

Núcleo y páginas

export const head

Lo único que sí llega al <head> real del documento (todo lo demás del layout termina dentro de <body>, por el splice del slot). icon/appleTouchIcon/stylesheets/meta — un objeto literal, mismo patrón que seo/schema.

Núcleo y páginas

Header con estado real: una isla en el layout

Un onClick directo en src/layout.tsx no se soporta (ids de nodo colisionarían entre layout y página). Una isla sí — el cliente lee specifier/props/estrategia del DOM, sin entrada en el manifiesto de activación, y sobrevive la navegación SPA sin remount.

SEO e i18n

seo{}

title/description/canonical/Open Graph/Twitter card por página. Cada campo es un string, una plantilla, o t("...") — nunca una función. Un campo que no se resuelve se omite, nunca se rellena a medias.

SEO e i18n

schema{} — JSON-LD real

Se resuelve a un <script type="application/ld+json"> real. type/@type es intercambiable; un @type explícito nunca se sobreescribe.

SEO e i18n

sitemap.xml y robots.txt automáticos

nexa build genera ambos para todas las rutas estáticas compiladas. nexa-seo avisa (NEXA-SEO-001..) si falta title/description/canonical, o si una imagen no tiene alt — nunca bloquea el build.

SEO e i18n

i18n básico: t() y [locale]

src/locales/<locale>.json es un diccionario plano. t("home.title") se resuelve contra el diccionario del locale actual — sin fallback a otro idioma: una clave ausente se omite (en seo) o queda inerte en el cuerpo.

SEO e i18n

Interpolación en t()

t("clave", { variable: data.x }) sustituye el placeholder correspondiente dentro del texto del diccionario. nexa build/nexa lint fallan con un error claro si una clave y sus argumentos no se corresponden.

SEO e i18n

hreflang automático

<link rel="alternate" hreflang="..."> se genera solo si la ruta vive bajo [locale] y hay más de un src/locales/*.json — sin escribirlo a mano.

Islas interactivas

Marcar una isla

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.

Islas interactivas

El contrato de mount()

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.

Islas interactivas

Vue real dentro de una isla

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.

Islas interactivas

Una librería de npm dentro de una isla

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.

Islas interactivas

Modelo de componentes liviano (solo en islas)

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.

@nexa/ui — Componentes visuales

Button

nx-btn + una variante (primary/outline). Sin declarar nada — nexa build detecta las clases nx-* y genera el CSS correspondiente.

@nexa/ui — Componentes visuales

Input

nx-input. Con aria-invalid="true" (que agrega @nexa/forms solo) ya tiene borde rojo, sin declarar nada aparte.

@nexa/ui — Componentes visuales

Card

nx-card + nx-card-title opcional.

@nexa/ui — Componentes visuales

Table

nx-table-wrap agrega scroll horizontal en pantallas chicas; nx-table-zebra alterna el fondo de las filas.

@nexa/ui — Componentes visuales

Badge

nx-badge + variante: primary/success/warning/danger/neutral.

@nexa/ui — Componentes visuales

Avatar

nx-avatar (círculo, 2.5rem por defecto) + nx-avatar-sm/-lg. Con un <img> adentro recorta a object-fit: cover.

@nexa/ui — Componentes visuales

Breadcrumbs

nx-breadcrumbs (contenedor) + nx-breadcrumbs-link — el "/" entre pasos es puro CSS (::after), no hace falta escribirlo. aria-current="page" marca el actual.

@nexa/ui — Componentes visuales

Alert

nx-alert + variante success/warning/danger (borde izquierdo de color). nx-alert-title opcional.

@nexa/ui — Componentes visuales

Divider

nx-divider (horizontal) / nx-divider-vertical.

@nexa/ui — Componentes visuales

Tooltip

nx-tooltip-content se muestra con :hover/:focus-within — accesible con teclado, sin una línea de JS.

@nexa/ui — Componentes visuales

Progress

nx-progress-bar necesita su width puesto a mano (fijo, o dinámico vía data.*) — Nexa no calcula ningún porcentaje.

@nexa/ui — Componentes visuales

Skeleton

nx-skeleton es un bloque con animación de shimmer; el desarrollador pone el width/height que necesite.

@nexa/ui — Componentes visuales

Utilidades de layout

Un set chico y deliberado, no un sistema de utilidades completo tipo Tailwind: nx-flex/nx-gap-N/nx-grid/nx-grid-cols-N/nx-stack.

@nexa/ui — Componentes visuales

Tema oscuro

Sin JS, el sitio ya respeta prefers-color-scheme del sistema. platform.theme.set("dark") deja que el usuario elija y le gane al sistema, persistiendo con platform.storage().

@nexa/ui — Interactivos, sin isla

Dialog

ui.openDialog(el)/ui.closeDialog(el) — foco atrapado, Escape cierra, devuelve el foco al elemento anterior. ui está siempre disponible, no hace falta declararlo en [imports].

@nexa/ui — Interactivos, sin isla

Apilamiento de Dialog

Abrir un Dialog mientras otro ya está abierto lo apila encima (z-index correcto) y oculta el de abajo de lectores de pantalla (aria-hidden) mientras esté cubierto.

@nexa/ui — Interactivos, sin isla

ui.confirm() / ui.alert()

Confirmar antes de una acción destructiva, o avisar que algo se guardó, sin escribir el <div class="nx-dialog"> a mano. Escape en confirm() cuenta como cancelar; en alert(), como aceptar.

@nexa/ui — Interactivos, sin isla

Drawer

Mismo contrato de accesibilidad que Dialog, pensado para sidebars/menús laterales en vez de una caja centrada.

@nexa/ui — Interactivos, sin isla

Toast / snackbar

ui.notify() — no confundir con platform.notify() (notificación real del sistema operativo): esta es efímera, dentro de la página. Se apila con otras, se auto-cierra a los 4s.

@nexa/ui — Interactivos, sin isla

Tabs

ui.selectTab(event) lee de qué botón vino el click y su data-tab, encuentra el .nx-tab-group más cercano, y hace el resto.

@nexa/ui — Interactivos, sin isla

Accordion

ui.toggleAccordionItem(event). Con data-exclusive="true" en el contenedor, abrir un item cierra los demás.

@nexa/ui — Interactivos, sin isla

Dropdown

ui.toggleDropdown(event) / ui.selectDropdownOption(event) — se cierra con click afuera o Escape, sin atrapar el foco (un dropdown no bloquea el resto de la página).

@nexa/ui — Interactivos, sin isla

Ordenar y filtrar una Table

ui.sortTable(event) ordena por la columna del <th> clickeado (numérico si ambas celdas lo son). ui.filterTable(table, query) oculta filas cuyo texto no matchea. Ambos client-side, sin re-pedir nada al backend.

@nexa/ui — Interactivos, sin isla

Buscador de página reactivo

ui.createPageSearch(container) filtra elementos data-searchable con un Signal real de @nexa/reactivity por debajo. El controlador se cuelga del propio <input> porque cada chunk es un módulo aislado.

@nexa/forms

Validación con data-nexa-form

data-nexa-form activa todo lo demás. Cada campo necesita name, conectado con <p data-nexa-error-for="ese-name">. Se valida al perder el foco la primera vez, y en cada cambio después.

@nexa/forms

Mensajes personalizados y clases automáticas

data-nexa-message reemplaza el mensaje nativo del navegador. Clases automáticas por campo: nx-touched, nx-dirty, nx-invalid, más aria-invalid.

@nexa/platform

platform.share()

Web: Web Share API. Capacitor: plugin @capacitor/share. Tauri: no soportado (lanza).

@nexa/platform

platform.notify()

Notificación real del sistema operativo. Web: Notification API (pide permiso). Capacitor: @capacitor/local-notifications.

@nexa/platform

platform.capturePhoto()

Web: getUserMedia + canvas. Capacitor: @capacitor/camera. Devuelve { dataUrl }.

@nexa/platform

platform.storage() / sessionStorage()

Mismo contrato get/set/remove sobre localStorage o sessionStorage — este último vive solo mientras dure la pestaña.

@nexa/platform

platform.cache()

Cache API directa, independiente de [pwa.cache] (que vive en el service worker) — para cachear algo puntual desde código normal.

@nexa/platform

platform.db()

Wrapper mínimo sobre IndexedDB, no un ORM. Cada nombre de colección es su propia base — sin declarar nada de antemano.

@nexa/platform

platform.network

Capacitor nativo usa @capacitor/network real; Web/Tauri usan navigator.onLine + eventos online/offline. type (wifi/cellular) es exclusivo de Capacitor.

@nexa/platform

platform.lifecycle

Capacitor nativo usa @capacitor/app (getState/appStateChange); Web/Tauri usan document.hidden + visibilitychange — la misma señal que usa la propia rama web de @capacitor/app.

@nexa/platform

platform.geolocation

Capacitor nativo usa @capacitor/geolocation; Web/Tauri usan navigator.geolocation — la misma API que usa la propia rama web de @capacitor/geolocation por dentro.

@nexa/platform

platform.deepLinks

Capacitor nativo usa @capacitor/app (getLaunchUrl/appUrlOpen). Web/Tauri: getLaunchUrl() siempre devuelve url vacía y onOpen() nunca dispara — así se comporta la propia rama web de @capacitor/app.

@nexa/platform

platform.push

Deliberadamente más chico que el plugin completo de Capacitor: solo registro + recibir. register() devuelve una unión discriminada porque Capacitor y Web no comparten forma de registro.

@nexa/platform

platform.biometrics

Capacitor nativo usa @aparajita/capacitor-biometric-auth. Web/Tauri usan WebAuthn real — no se replicó la rama web de ese plugin porque es una simulación deliberada, no biometría real.

@nexa/platform

platform.haptics

Capacitor nativo usa @capacitor/haptics real. Web/Tauri usan navigator.vibrate — la misma API que usa la propia rama web de @capacitor/haptics.

@nexa/reactivity

state() — Signal

.value lee y suscribe; .peek() lee sin suscribir. Escribir .value dispara los efectos que la leyeron, agrupado por microtask.

@nexa/reactivity

computed()

Un ReadonlySignal que se recalcula solo. Encadenar computeds funciona, con un costo real: cada salto es una vuelta más de microtask.

@nexa/reactivity

effect()

Corre ya, y de nuevo cada vez que cambie algo que leyó. Devuelve una función para desactivarlo.

@nexa/reactivity

watch()

Como effect, pero NO corre al crearse — solo en cambios posteriores. Recibe el valor nuevo y el viejo.

@nexa/reactivity

bindText()

Lo que el compilador genera automáticamente para {data.x} en el cuerpo de una página — no es algo que normalmente escribas a mano.

@nexa/reactivity

mountComponent() — solo dentro de islas

No aplica a páginas Nexa Core. Component<P>, props tipadas, y limpieza encadenada — sin Virtual DOM.

@nexa/http

createApi()

get/post/put/delete reales. Un status no-2xx lanza HttpError { status, message }.

@nexa/http

query()

data/loading/error como Signal de @nexa/reactivity. cachePolicy: cache-first (default) | network-first | stale-while-revalidate.

@nexa/http

mutation()

Mismos Signal (data/loading/error) que query(), para una acción que el usuario dispara (crear, editar, borrar).

@nexa/http

connectSSE()

Envoltorio delgado sobre EventSource nativo. data es el último mensaje, parseado como JSON si se puede.

@nexa/http

connectSocket()

Envoltorio sobre WebSocket nativo. status refleja el ciclo de vida real; send() serializa objetos como JSON automáticamente.

@nexa/http

Reconexión con backoff

reconnect: true (o un objeto para ajustar los valores) reconecta solo con backoff exponencial + jitter. status pasa por "reconnecting" mientras lo intenta.

Terceros y vendoring

CSS de terceros: un <link> normal

Nexa nunca procesa ni entiende ese CSS, así que no hace falta ningún paso especial.

Terceros y vendoring

JS con build global (UMD): un <script> normal

Deja una variable global — como un chunk copia el handler tal cual, podés usarla directo en un onClick, sin declarar nada en nexa.toml.

Terceros y vendoring

Módulos ES puros: [imports]

Mismo mecanismo que usan platform/ui. El chunk detecta nombre. en el handler y antepone el import.

Terceros y vendoring

Vendorizar un paquete real de npm

Cuando tiene dependencias propias o viene en CommonJS: instalar, un entry.js, y esbuild --bundle --format=esm a un único archivo bajo public/vendor/.

Imágenes, PWA y rendimiento

Imágenes optimizadas automáticamente

Sin configuración: cualquier <img src> estático de más de 480px se convierte a <picture> con variantes AVIF reales en varios anchos, con width/height/loading="lazy" completados solos.

Imágenes, PWA y rendimiento

PWA

nexa add pwa agrega [pwa] a nexa.toml. nexa build genera manifest.webmanifest y sw.js reales; cada página lleva el <link rel="manifest"> y el registro del service worker solos.

Imágenes, PWA y rendimiento

Presupuestos de rendimiento

Con esto declarado, nexa build falla (no solo avisa) si una página se pasa — nombrando exactamente qué se excedió.

Imágenes, PWA y rendimiento

Telemetría

Sin el endpoint explícito, @nexa/telemetry nunca se carga. Con él, cada página manda Core Web Vitals (LCP/CLS/INP) y errores sin capturar.

Nativo, despliegue y CLI

Tauri (escritorio)

Genera un binario real de Windows/macOS/Linux, compilado con cargo — mismo código fuente que la web.

Nativo, despliegue y CLI

Capacitor (Android/iOS)

Genera un proyecto real de Android/iOS. El build de Android se verificó de punta a punta (APK real compilado con Gradle); iOS necesita Xcode.

Nativo, despliegue y CLI

Despliegue con nginx

Genera deploy/nginx.conf real: gzip, cabeceras de seguridad, caché immutable de un año solo para archivos con hash, y un proxy_pass real para rutas dinámicas sin paths.

Nativo, despliegue y CLI

El CLI completo

nexa build/preview/dev/lint/test/add/info — lint falla si hay avisos SEO/paquetes; test compila (dist/ fresco) y corre el test runner del proyecto.

Nativo, despliegue y CLI

nexa.toml — referencia completa

Todas las secciones son opcionales salvo [project]. Ninguna requiere package.json ni npm.

Nativo, despliegue y CLI

@nexa/test

Para probar un chunk de activación aislado, fuera del navegador real — mountChunk/getEntry/expectEntry contra el manifiesto real.