Guías

Caché

Mantén las páginas de tu sitio en el borde y purga exactamente lo que cambió al publicar, editar o despublicar, en segundos.

Caché

Una página que lee Hollware no tiene que renderizarse para cada lector. Hollware sabe exactamente qué cambió cuando publicas, editas o despublicas una entrada, así que tu sitio mantiene sus páginas en el borde y purga solo las que la mostraban. La mayoría de las solicitudes entonces no ejecuta nada, y un cambio se ve en segundos en todas partes.

Con Nuxt

Actívalo en nuxt.config.ts:

export default defineNuxtConfig({
  modules: ['@hollware/nuxt'],
  hollware: { site: 'my-site', cache: 'purge' },
})

y dale al Worker del sitio su caché en wrangler.jsonc:

{
  "cache": { "enabled": true },
}

Desde ahí, cada página la guarda Workers Cache de Cloudflare, que la sirve sin ejecutar tu Worker, etiquetada con lo que mostraba. Los errores, las escrituras y las páginas que no leen nada nunca se guardan, y el navegador no guarda nada: solo el borde.

Luego dile a Hollware adónde enviar sus eventos. En el admin, en Sitio, agrega un webhook llamado site con la URL https://your-site.example/_hollware/webhook. Hollware crea su secreto y lo muestra una sola vez: configúralo en el Worker del sitio.

npx wrangler secret put NUXT_HOLLWARE_WEBHOOK_SECRET

A partir de ese momento, cada publicación, edición y despublicación purga las páginas que mostraban esa entrada, sus listas y las páginas que enlazan a sus traducciones, y un cambio en la estructura del sitio (una colección, una ruta, un locale) purga las páginas que muestran la estructura y todas las listas. En hollware.com, una página publicada se ve unos ocho segundos después de aprobarse.

Consejo
Con cache: 30, en cambio, cada página se guarda 30 segundos en cada isolate, sin webhook: es más simple, y un cambio se ve dentro de ese plazo.

El contrato, para cualquier otro stack

Cada evento que envía Hollware trae cacheTags, las etiquetas que el cambio invalida:

{
  "kind": "entry.published",
  "entry": { "id": "ent_01JAB3XQ8ZK4M6N2P5R7S9T0VW", "collection": "blog", "locale": "en", "slug": "hello-world" },
  "path": "/blog/hello-world/",
  "cacheTags": ["entry:ent_01JAB3XQ8ZK4M6N2P5R7S9T0VW", "list:blog:en", "list:blog:*", "group:blog:hello-world"]
}

Un cambio en la estructura del sitio envía site.changed, que no trae ninguna entrada, solo las etiquetas: site y las listas de cada colección en cada locale que el sitio tenía o tiene.

Etiqueta cada página con lo que muestra, con los mismos nombres, y purga las etiquetas de cada evento:

EtiquetaUna página que
entry:<id>muestra la entrada, sola o junto a otras
list:<collection>:<locale>lista las entradas de una colección en un locale
list:<collection>:*las lista en todos los locales
group:<collection>:<group>enlaza a las traducciones de un grupo
sitemuestra la estructura del sitio, como su navegación

@hollware/core exporta las funciones que las generan: entryTag, listTag, groupTag, tagsOfChange y tagsOfSiteChange. Verifica la firma de cada evento con verifyWebhook antes de purgar cualquier cosa.

import { parseHollwareEvent, verifyWebhook } from '@hollware/core'

const body = await request.text()
const ok = await verifyWebhook({
  secret: env.HOLLWARE_WEBHOOK_SECRET,
  body,
  headers: request.headers,
  // Rechaza un evento que ya recibió, por el id del cuerpo firmado: también se rechaza una
  // solicitud capturada y reenviada dentro de los cinco minutos de tolerancia. Guarda cada id un día.
  isNew: async (id) => {
    if ((await env.SEEN.get(id)) !== null) return false
    await env.SEEN.put(id, '1', { expirationTtl: 86_400 })
    return true
  },
})
if (!ok) return new Response(null, { status: 401 })
const event = parseHollwareEvent(JSON.parse(body))

verifyWebhook solo, sin el resto de @hollware/core, está en @hollware/client/webhooks, que no importa nada: un sitio con otra versión mayor de zod verifica sus entregas con él.

Un reintento de una entrega lleva el mismo id: si tu receptor puede fallar después de que isNew registró un id, regístralo solo cuando el evento ya esté procesado, para que el reintento no se rechace.