CreaRack-SL

Version Banner — Auto-aviso de nueva versión tras deploy

Descripción general

El Version Banner es un componente React sticky que detecta en tiempo real cuando se ha desplegado una nueva versión del workspace CreaRack Pro y avisa al usuario con un banner no intrusivo en la parte superior del viewport.

Implementado en la sesión s69 (18-05-2026) como «Opción B» del plan de notificación de versiones: polling cliente → sin WebSockets, sin dependencias extra, compatible con Cloudflare Pages.


Motivación

Los usuarios podían tener el workspace abierto durante horas (o días). Tras un deploy, trabajaban sobre código viejo sin saberlo, lo que podía producir inconsistencias con APIs o comportamientos inesperados. La solución fuerza una decisión informada del usuario sin interrumpir datos no guardados.


Arquitectura

Flujo completo

[CF Pages build]
  └─ node scripts/generate-version.mjs
       └─ escribe public/version.json  { commit_sha, commit_sha_full, build_at }

[Browser, cada 60s]
  └─ fetch('/version.json', { cache: 'no-store' })
       └─ compara commit_sha con el valor inicial
            ├─ igual → nada
            └─ diferente → muestra <VersionBanner />

Archivos implicados

ArchivoRol
scripts/generate-version.mjsScript Node.js que genera public/version.json en cada build
public/version.jsonArtefacto de build (gitignoreado); contiene commit_sha + build_at
src/components/VersionBanner.tsxComponente React con polling + UI del banner
src/layouts/SecondaryLayout.astroMonta <VersionBanner client:load /> en todas las páginas

Componente VersionBanner.tsx

Props: ninguna (self-contained).

Estado interno:

  • initial: VersionInfo | null — versión capturada al cargar la página.
  • latest: VersionInfo | null — última versión obtenida por polling.
  • dismissed: boolean — el usuario ha pulsado «Más tarde».

Comportamiento:

  • Se desactiva automáticamente en localhost (evita falsos positivos en dev).
  • Intervalo de polling: 60 segundos (POLL_MS = 60_000).
  • Usa { cache: 'no-store' } para evitar que la CDN de Cloudflare sirva el JSON cacheado.
  • El banner no fuerza recarga — el usuario elige «Recargar ahora» o «Más tarde».
  • «Más tarde» hace dismissed = true; si tras otro poll hay otra versión nueva distinta, el banner reaparece.
  • Accesibilidad: role="status" + aria-live="polite".

Script generate-version.mjs

Escrito en ESM puro (Node.js ≥18). Se ejecuta como paso previo a astro dev y astro build.

Resolución del SHA:

  1. Si existe la env var CF_PAGES_COMMIT_SHA (inyectada por Cloudflare Pages en build), la usa directamente.
  2. Fallback: git rev-parse HEAD mediante execSync.
  3. Si falla ambos: 'unknown'.

Salida (public/version.json):

{
  "commit_sha": "3e6a472",
  "commit_sha_full": "3e6a47239ed9a364e01643d29b5b978f0f44571d",
  "build_at": "2026-05-18T13:03:01.000Z"
}

El archivo está en .gitignore (se regenera en cada build; committearlo causaría ruido en el historial).


Integración en el layout

SecondaryLayout.astro monta el componente con la directiva client:load, que garantiza hidratación inmediata al cargar la página:

<AppLayout title={title} description={description}>
  <VersionBanner client:load />
  <div class="app">
    ...
  </div>
</AppLayout>

Como SecondaryLayout es el layout base de todas las páginas del workspace que extienden AppLayout, el banner queda disponible globalmente.


UX y diseño

  • Posición: position: fixed; top: 0; z-index: 9999 — encima de cualquier otro elemento.
  • Color: mezcla color-mix(in srgb, var(--accent) 92%, black) para heredar el tema activo.
  • Iconografía: SVG inline (estilo Lucide) con el icono de «refresh» circular.
  • Botones: clases CSS centralizadas .btn.primary.sm (Recargar) y .btn.ghost.sm (Más tarde).
  • Información mostrada: commit_sha inicial → commit_sha nuevo (ej. 27aa041 → 3e6a472).

Decisiones de diseño (Opción B vs. alternativas)

AlternativaDescartada porque
Opción A — SSE / WebSocket pushRequiere worker CF durable o server-sent events; complejidad desproporcionada para workspace interno
Opción B (esta) — Polling cliente 60sSimple, sin estado servidor, compatible con CF Pages estático. Latencia máxima = 60s
Opción C — Service Worker + cache bustingMayor complejidad de setup; requiere gestionar versiones del SW

Limitaciones conocidas

  • Latencia máxima de 60 s entre deploy y aviso visible. Aceptable para workspace interno.
  • Si el usuario tiene varias pestañas abiertas, cada una hace su propio polling (no coordinación entre tabs).
  • En localhost el banner nunca aparece (by design).
  • Si version.json no está presente (primera build sin el script), fetch devuelve 404 → initial queda null → banner nunca se muestra (fallo silencioso seguro).

Historial

SesiónCommitDescripción
s693e6a472Implementación inicial completa

Véase también

  • [[workspace—que-es-workspace]]