Swappit es una librería JavaScript ligera que permite actualizar parcial o totalmente el contenido HTML de tu sitio web sin recargar la página. Con un enfoque declarativo basado en atributos data personalizados, facilita la creación de experiencias de nav
npm install @soyleninjs/swappitSwappit es una librería JavaScript ligera que permite actualizar parcial o totalmente el contenido HTML de tu sitio web sin recargar la página. Con un enfoque declarativo basado en atributos data personalizados, facilita la creación de experiencias de navegación modernas sin la complejidad de un framework completo o SPA.
Características principales:
- Actualización parcial del DOM: Reemplaza solo los elementos que necesitas usando identificadores únicos (handles)
- Tres formas de uso: API JavaScript, links automáticos con data-swappit-handle, o componente
- Precarga inteligente: Configura precarga instantánea o al hacer hover, a nivel global o por link individual
- Navegación con historial: Soporte para botones adelante/atrás del navegador
- Sistema de caché: Controla cuándo usar caché o forzar nuevas descargas
- Detección automática: Observador de DOM que configura nuevos links dinámicamente
- Sistema de eventos: Escucha eventos antes/después de actualizar y al reiniciar
- Logging colorido: Sistema de debugging con 4 niveles (info, success, warning, error)
- Zero-config: Funciona con configuración mínima, personalizable según necesites
Puedes integrar Swappit en tu proyecto de las siguientes formas:
``bash`
npm install @soyleninjs/swappit
Importa en tu proyecto:
`javascript
// ES modules
import Swappit from '@soyleninjs/swappit';
// O desde CDN
import Swappit from "https://esm.sh/@soyleninjs/swappit";
// CommonJS
const Swappit = require('@soyleninjs/swappit');
`
`html`
1. Descarga swappit.min.js desde GitHub Releases
2. Inclúyelo en tu HTML:
`html`
Nota: El archivo swappit.min.js incluye tanto la clase Swappit como el componente .
Swappit ofrece tres formas principales de uso:
`htmlContenido original del headerContenido original del main
data-log
data-update-url
data-enable-history
data-preload="hover">
`
`htmlContenido original del headerContenido original del main
Página 1
Página 2 (Precarga al pasar el mouse)
Página 3 (Precarga instantánea)
`
`html`
HTML: Contenido original
`html`
Título original
JavaScript:
`javascript`
const appBasico = new Swappit('mi-app');
function actualizarContenido() {
appBasico.update('./contenido-nuevo.html');
}
HTML:
`html`Sección 1 (Orden: 2)Sección 2 (Orden: 1)Sección 3 (Orden: 3)
JavaScript:
`javascript`
const appOrdenado = new Swappit('mi-app-orden');
appOrdenado.update('./contenido-ordenado.html');
HTML:
`html`.........
JavaScript:
`javascript`
const appPrecarga = new Swappit('mi-app-precarga');
appPrecarga.preloadContents(['./header.html', './main.html', './footer.html']);
function actualizarHeader() {
appPrecarga.update('./header.html');
}
function actualizarMain() {
appPrecarga.update('./main.html');
}
function actualizarFooter() {
appPrecarga.update('./footer.html', false);
}
`javascript`
new Swappit(handle, log = false, options = {})
| Parámetro | Tipo | Descripción |
|-----------|------|-------------|
| handle | string | Identificador único para la instancia (obligatorio) |log
| | boolean | Activa/desactiva los logs de la consola (opcional, default: false) |options
| | object | Configuración avanzada (ver tabla abajo) |
| Opción | Tipo | Default | Descripción |
|--------|------|---------|-------------|
| updateUrl | boolean | false | Actualiza la URL en la barra del navegador al hacer update |enableHistory
| | boolean | false | Habilita navegación con botones adelante/atrás del navegador. Requiere updateUrl: true |preload
| | string | false | Modo de precarga por defecto para links con data-swappit-handle. Valores: false, "hover", "instant" |
Notas:
- updateUrl: true + enableHistory: false: actualiza la URL sin agregar al historial (usa replaceState)updateUrl: true
- + enableHistory: true: actualiza la URL y agrega al historial (usa pushState)preload
- : define el comportamiento por defecto para links, pero puede ser sobreescrito individualmente con el atributo data-preload en cada link
| Atributo | Descripción |
|----------|-------------|
| data-[handle]-update | Identificador del elemento a actualizar (obligatorio) |data-[handle]-update-order
| | Orden de actualización (opcional, numérico). Los elementos sin orden se actualizan primero, luego los ordenados de menor a mayor |
| Atributo | Tipo | Descripción |
|----------|------|-------------|
| data-swappit-handle | string | Conecta el link con una instancia Swappit (obligatorio) |data-preload
| | string | Modo de precarga: "instant" (inmediata), "hover" (al pasar mouse/touch), o sin definir (sin precarga) |data-load-from-cache
| | boolean | Si es true usa caché, si es false fuerza nueva descarga al hacer click |
| Método | Descripción |
|--------|-------------|
| update(url, loadFromCache = true) | Actualiza el contenido desde una URL relativa. url
- : Ruta relativa loadFromCache
- : Usa caché (true) o fuerza descarga (false) |preloadContents(arrayUrls)
| | Precarga el contenido de múltiples URLs relativas |reinit(log, options)
| | Reinicia la instancia limpiando la caché, actualizando opciones y volviendo a observar el DOM. log
- : Nuevo valor para logging options
- : Nuevas opciones para merge |
| Método | Descripción |
|--------|-------------|
| updateScriptByContent(arrayScriptsNodes) | Actualiza scripts inline por contenido |updateScriptBySrc(matchUrl)
| | Actualiza scripts por URL de origen (agrega timestamp) |Swappit.instances
| | Map con todas las instancias Swappit creadas, indexadas por handle |
Swappit emite eventos personalizados que puedes escuchar:
| Evento | Cuándo se emite | Detalle (e.detail) |swappit:[handle]:beforeUpdate
|--------|-----------------|---------------------|
| | Antes de actualizar el DOM | { handle: string, url: string } |swappit:[handle]:afterUpdate
| | Después de actualizar el DOM | { handle: string, url: string } |swappit:[handle]:reinit
| | Después de reiniciar la instancia | { handle: string, url: "" } |
Ejemplo de uso:
`javascript
window.addEventListener('swappit:mi-handle:beforeUpdate', (e) => {
console.log('Comenzando actualización', e.detail);
// e.detail = { handle: 'mi-handle', url: './pagina.html' }
});
window.addEventListener('swappit:mi-handle:afterUpdate', (e) => {
console.log('Contenido actualizado', e.detail);
// Aquí puedes reinicializar scripts, ejecutar animaciones, etc.
});
window.addEventListener('swappit:mi-handle:reinit', (e) => {
console.log('Instancia reiniciada', e.detail);
});
`
Swappit incluye un sistema de logging con niveles: info (azul), success (verde), warning (amarillo), error (rojo).
Actívalo pasando true como segundo parámetro:
`javascript`
const app = new Swappit('mi-app', true);
Cada instancia debe tener un handle único, que se usará como prefijo en los atributos data:
`javascript`
const app1 = new Swappit('mi-app'); // data-mi-app-update
const app2 = new Swappit('otro-app'); // data-otro-app-update
Puedes precargar contenido y luego actualizarlo usando la caché:
`javascript`
app.preloadContents(['./header.html', './main.html', './footer.html']);
app.update('./header.html'); // Usa caché
app.update('./footer.html', false); // Fuerza descarga
IMPORTANTE: Swappit solo acepta URLs relativas internas por seguridad:
`javascript
// ✅ URLs válidas
app.update('/pagina.html');
app.update('./pagina.html');
app.update('../pagina.html');
// ❌ URLs inválidas (lanzarán error)
app.update('https://ejemplo.com/pagina.html'); // URL externa
app.update('pagina.html'); // No empieza con / ni ./
`
Esta validación se aplica a:
- Método update(url)preloadContents(arrayUrls)
- Método href
- Atributo de links con data-swappit-handle
Las páginas de destino deben tener elementos con los mismos atributos data-[handle]-update que la página principal. Swappit solo actualiza los elementos que tienen correspondencia por nombre.
Ejemplo:
Página principal:
`html`Encabezado originalBarra lateral originalContenido original`
Página destino:html`Nuevo encabezadoNuevo contenidoEste elemento será ignorado
Resultado: solo se actualizan los elementos que tienen correspondencia.
Consejos:
- Usa los mismos nombres de atributos en todas tus páginas
- Divide el contenido en componentes lógicos
- Si necesitas orden, usa data-[handle]-update-order
)Swappit incluye un sistema de observación del DOM que detecta automáticamente links con el atributo data-swappit-handle y los configura para actualizar el contenido sin recargar la página.
`html
Cada link puede tener su propia configuración de precarga:
`html
Página 1
Puedes definir un modo de precarga predeterminado para todos los links al crear la instancia:
`javascript`
const app = new Swappit('mi-app', false, {
preload: 'hover' // Todos los links harán precarga al hover por defecto
});
Los links individuales pueden sobrescribir este comportamiento:
`html
Página 1
Swappit observa cambios en el DOM y configura automáticamente los nuevos links que se agreguen dinámicamente:
`javascript
// Los nuevos links se configurarán automáticamente
document.querySelector('#contenedor').innerHTML =
Nueva Página;`
- Zero-config: Solo agrega el atributo data-swappit-handle a tus links
- Precarga flexible: Configura precarga individual o global
- Detección automática: Los links dinámicos se configuran automáticamente
- Control de caché: Decide si usar caché o forzar descarga por link
Swappit incluye el custom element para crear instancias Swappit de forma declarativa usando atributos HTML.
`html`
| Atributo | Tipo | Descripción | Valor predeterminado |
|----------|------|-------------|----------------------|
| data-handle | string | Identificador de la instancia Swappit (obligatorio) | N/A |data-log
| | boolean | Activa logs para la instancia | false |data-update-url
| | boolean | Actualiza la URL del navegador | false |data-enable-history
| | boolean | Habilita navegación con botones del navegador | false |data-preload
| | string | Modo de precarga: "instant", "hover" o false | false |data-load-from-cache
| | boolean | Usa caché por defecto | true |data-destroy-after-remove
| | boolean | Elimina la instancia del registro cuando el componente se desconecta del DOM | false |
1. Crea o reinicia una instancia: Si no existe una instancia con ese data-handle, la crea. Si ya existe, la reinicia con las nuevas opciones.data-swappit-handle
2. Configuración declarativa: Todos los atributos se mapean directamente a las opciones de Swappit.
3. Funciona con links automáticos: Los links con que coincidan con el handle se configuran automáticamente.reinit()
4. Reinicio automático: Si el componente ya tiene una instancia activa y se especifican nuevos atributos, llama a para actualizar la configuración.data-destroy-after-remove
5. Cleanup opcional: Si está activo, cuando el componente se elimina del DOM, también se elimina la instancia del registro Swappit.instances.
`html
Encabezado Original
Contenido original de la página
data-log
data-update-url
data-enable-history
data-preload="hover">
`
El método reinit() permite reiniciar una instancia Swappit, limpiando su caché y actualizando su configuración sin necesidad de crear una nueva instancia.
`javascript`
instance.reinit(log, options)
- log (boolean): Nuevo valor para activar/desactivar loggingoptions
- (object): Objeto con opciones para actualizar (se hace merge con las existentes)
1. Limpia la caché: Elimina todo el contenido almacenado en contentsCacheswappit:[handle]:reinit
2. Actualiza logging: Cambia el estado de logging
3. Actualiza opciones: Hace merge de las nuevas opciones con las existentes
4. Reinicia handlers: Vuelve a configurar el handler de historial
5. Reinicia observer: Vuelve a observar el DOM para detectar nuevos links
6. Emite evento: Dispara el evento
`javascript
const app = new Swappit('mi-app', false, {
updateUrl: false,
preload: false
});
// Después de un tiempo, cambiar la configuración
app.reinit(true, {
updateUrl: true,
enableHistory: true,
preload: 'hover'
});
// Ahora la instancia tiene:
// - log: true
// - updateUrl: true
// - enableHistory: true
// - preload: 'hover'
// - caché limpiada
`
- Cuando necesitas cambiar opciones dinámicamente
- Cuando detecta que ya existe una instancia con ese handle
- Cuando quieres limpiar la caché sin perder la instancia
- Al cambiar entre modos (por ejemplo, de desarrollo a producción)
IMPORTANTE: En la versión actual de Swappit, los scripts dentro de los elementos actualizados NO se ejecutan automáticamente.
Cuando Swappit actualiza el DOM:
- Los elementos HTML se reemplazan correctamente
- Los
Los scripts automáticos están comentados en el código para evitar:
- Ejecución duplicada de scripts
- Problemas con librerías que no soportan reinicialización
- Comportamientos inesperados en aplicaciones complejas
Esto te da control total sobre qué scripts ejecutar y cuándo.
| Problema | Posible causa | Solución |
|----------|---------------|----------|
| No se actualiza el contenido | Atributos data incorrectos o handle distinto | Verifica que los atributos data-[handle]-update coincidan entre la página principal y las páginas de destino |/
| Errores en consola sobre URL inválida | URL externa o absoluta | Solo se permiten rutas relativas internas que empiecen con o ./ |data-swappit-handle
| Links no funcionan automáticamente | Falta atributo | Agrega data-swappit-handle="tu-handle" a los links |data-[handle]-update-order
| Orden de actualización incorrecto | Falta atributo order | Añade con valores numéricos. Los sin orden se actualizan primero |Swappit.instances.get('tu-handle')
| Error "El handle ya está en uso" | Intentas crear dos instancias con el mismo handle | Usa para reutilizar una instancia existente, o usa que reinicia automáticamente |
| no crea la instancia | Falta atributo data-handle | El atributo data-handle es obligatorio |Swappit.updateScriptByContent()
| Los scripts no se ejecutan | Scripts desactivados por defecto | Usa o Swappit.updateScriptBySrc() en el evento afterUpdate |data-preload
| La precarga no funciona | Valor incorrecto en | Usa "instant" o "hover" (entre comillas) |updateUrl: true
| Los botones adelante/atrás no funcionan | Falta configuración de historial | Activa y enableHistory: true en las opciones |log: true
| Links dinámicos no se configuran | Error en el observer | El observer se inicia automáticamente. Activa para ver mensajes de depuración |loadFromCache
| El caché no se actualiza | está en true | Usa loadFromCache: false o llama a update(url, false) para forzar nueva descarga, o usa reinit() para limpiar la caché |reinit(log, options)` para actualizar opciones dinámicamente |
| La instancia no toma las nuevas opciones | Las opciones se definen al crear la instancia | Usa el método