---
title: Caché
description: Mantén las páginas de tu sitio en el borde y purga exactamente lo que cambió al publicar, editar o despublicar, en segundos.
section: guides
order: 7
---

# 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`:

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

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

```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.

```sh
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.

::callout{type="tip"}
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:

```json
{
  "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:

| Etiqueta | Una 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 |
| `site` | muestra 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.

```ts
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.
