Aplicaciones web sin servidor propio: ESM y CDN

Fecha de publicación: 2024-07-04

Una aplicación web pequeña ya no necesita siempre infraestructura compleja. Los módulos ES y las CDN permiten ejecutar código directamente en el navegador: se publica una página estática y las bibliotecas llegan por red. Veámoslo con un ejemplo.

La aplicación de demostración es un chat que vive en el cliente, carga bibliotecas desde jsDelivr y se comunica con una API externa. Su index.html está en GitHub Pages.

Una vez publicado un paquete en npm, el navegador puede recibirlo mediante una CDN como jsDelivr o unpkg.

De qué se compone el ejemplo

La interfaz utiliza Vue, Vue Router y Quasar. La navegación es mínima: chat, configuración e información.

En la configuración se eligen modelo e instrucción de sistema. Una clave secreta introducida en el navegador debe considerarse accesible desde ese dispositivo y sus extensiones; para un producto real es preferible un intermediario de servidor con credenciales limitadas, no entregar una clave API permanente al cliente.

index.html

El punto de entrada es muy compacto: enlaza estilos, fuentes, un importmap y el módulo principal.

<script type="importmap">
{ "imports": {
  "vue": "https://cdn.jsdelivr.net/npm/vue@3.4.31/dist/vue.esm-browser.prod.js",
  "openai/core": "https://cdn.jsdelivr.net/npm/openai@4.52.2/core.mjs"
} }
</script>
<script type="module">
import app from 'https://cdn.jsdelivr.net/npm/@flancer64/demo-wa-esm-openai@0.1.0/src/App.mjs';
app.mount('#app');
</script>

El importmap ofrece al navegador nombres de importación parecidos a los de Node. El documento también carga recursos y monta la aplicación en el elemento de la página.

El paquete de la aplicación

@flancer64/demo-wa-esm-openai está compuesto por módulos ES. Mod/ contiene modelos de acciones y Ui/, componentes Vue.

En App.mjs, las versiones ESM de Vue y Vue Router se importan de forma estática. La versión mostrada de Quasar era una biblioteca UMD, así que antes de importarla dinámicamente recibe Vue por el objeto global:

import * as Vue from 'https://cdn.jsdelivr.net/npm/vue@3.4.31/dist/vue.esm-browser.prod.js';
window.Vue = Vue;
await import('https://cdn.jsdelivr.net/npm/quasar@2.16.4/dist/quasar.umd.prod.js');
const Quasar = window.Quasar;

Las rutas cargan componentes de forma diferida: el navegador descarga un componente solo al visitar su pantalla.

const routes = [
  { path: '/', component: () => import('./Ui/Route/Chat.mjs') },
  { path: '/config', component: () => import('./Ui/Route/Config.mjs') },
];

Lo que ve el navegador

La pestaña Sources revela que el alojamiento estático entrega únicamente index.html y estilos; el paquete y las dependencias llegan desde la CDN. Las rutas no visitadas no cargan sus componentes. Las fuentes e imágenes también pueden estar en orígenes públicos, y la configuración del usuario, en almacenamiento local.

Conclusión

El stack actual permite crear y distribuir aplicaciones pequeñas sin servidores virtuales propios: el código y las dependencias pueden publicarse en servicios abiertos. Las CDN aportan buena velocidad y caché en los siguientes arranques.

Los módulos se pueden descargar con la granularidad de la acción de la persona usuaria, sin construir bundles específicos ni hacer tree-shaking de antemano. La contraparte es una cadena de suministro abierta: aumenta el riesgo de código malicioso o cambiado inesperadamente. Fije versiones, evalúe la confianza en paquetes y CDN, use CSP y no guarde secretos importantes en el cliente. Para una aplicación abierta y pequeña este enfoque es práctico; con datos sensibles, los mismos principios ESM se pueden usar desde infraestructura propia.

Fragmentos adicionales de código fuente

});
const app = createApp(Main);
app.use(router);
app.use(Quasar, {
}
});
export default app;
{path: …, component: () => import(‘./Ui/Route/About.mjs’)}