createCloudflareAssetReader
Sirve desde el binding de Static Assets de Cloudflare sólo los archivos del build listados en el manifiesto, con el ETag, HEAD, 304 y la caché de los demás adaptadores.
import { createCloudflareAssetReader } from "@meekojs/meeko/cloudflare";createCloudflareAssetReader({ binding, assets }) es el lector de archivos públicos de Workers. El wrangler.jsonc que genera Meeko declara los assets con run_worker_first: true y html_handling/not_found_handling en "none", así que todas las peticiones llegan al Worker; este lector responde sólo a las rutas del manifiesto de assets del build, leyéndolas del binding ASSETS, y devuelve null para las demás.
Así un Worker sirve los archivos con las mismas reglas que Node, Bun y Deno: nada fuera del manifiesto, el mismo ETag y la misma política de caché.
Uso#
import { createCloudflareAssetReader, createWorker } from "@meekojs/meeko/cloudflare";
import type { CloudflareAppContext } from "@meekojs/meeko/cloudflare";
function createCloudflareApp({ env, platform }: CloudflareAppContext<Env>) {
return createApp({
production: true,
platform,
assets: createCloudflareAssetReader({ binding: env.ASSETS, assets: manifest.assets ?? {} }),
});
}
export default createWorker(createCloudflareApp);Tipo#
function createCloudflareAssetReader(options: CloudflareAssetReaderOptions): AssetReaderinterface CloudflareAssetReaderOptions {
readonly binding: CloudflareAssetsBinding
readonly assets: AssetManifest
}interface CloudflareAssetsBinding {
fetch(request: Request): Promise<Response>
}interface AssetReader {
get(pathname: string, request: Request): Promise<Response | null>
}Parámetros#
| Opción | Tipo | Descripción |
|---|---|---|
binding |
CloudflareAssetsBinding |
El binding de Static Assets, normalmente env.ASSETS: un objeto con fetch(request). |
assets |
AssetManifest |
Las rutas públicas con su type, etag, size e immutable. |
Valor devuelto#
Un AssetReader con get(pathname, request): null para una ruta que no está en assets o un método distinto de GET y HEAD; 304 si If-None-Match coincide, sin leer del binding; 200 con el cuerpo del binding, content-type, ETag, content-length y cache-control (immutable un año para los archivos con hash, max-age=0, must-revalidate para el resto).
Ejemplos#
La salida de meeko build --adapter cloudflare#
.meeko/output/cloudflare/
worker.js ← createWorker y la clase de salas, un solo módulo
wrangler.jsonc ← assets: { directory: "./assets", binding: "ASSETS", run_worker_first: true }
assets/ ← build cliente y public/
assets/_meeko/prerender/ ← páginas prerenderizadas, que el Worker lee y nunca sirve como archivosComprobar que un archivo del build no se publica#
curl -s -o /dev/null -w "%{http_code}\n" https://mi-app.example/_meeko/prerender/manifest.json # 404
curl -s -o /dev/null -w "%{http_code}\n" https://mi-app.example/worker.js # 404Errores comunes#
Un archivo listado que falta en los assets#
assets/ subido sin la carpeta assets/assets/ (un despliegue parcial)get rechaza con Error: Missing build asset /assets/entry-4f2a.js; la aplicación responde 500 y lo envía a onError. Despliegue la carpeta de salida completa con wrangler deploy --config .meeko/output/cloudflare/wrangler.jsonc.
npx wrangler deploy --config .meeko/output/cloudflare/wrangler.jsoncUn public/_meeko/#
public/_meeko/logo.svg_meeko/ de los assets está reservado para las páginas prerenderizadas: meeko build --adapter cloudflare se detiene con public/_meeko está reservado para la salida de Cloudflare de Meeko; cámbiale el nombre.
public/brand/logo.svgCambiar assets en server.wrangler#
server: { adapter: "cloudflare", wrangler: { assets: { directory: "./public", not_found_handling: "single-page-application" } } }meeko build --adapter cloudflare se detiene con TypeError: server.wrangler.assets is generated by Meeko and cannot be overridden (lo mismo con main, no_bundle y find_additional_modules): el Worker debe ver cada petición para aplicar el manifiesto, las sesiones y la CSP.
server: { adapter: "cloudflare", wrangler: { routes: [{ pattern: "mi-app.example", custom_domain: true }] } }Notas#
- Seguridad. Las rutas se buscan en el manifiesto sin decodificar y la URL que se pide al binding sale de la clave del manifiesto, nunca de la petición.
- Coste. Con
run_worker_first, cada archivo es una invocación del Worker; los archivos con hash llevanimmutabley el CDN de Cloudflare y el navegador los guardan un año. - CSP y cabeceras (desde 1.7).
server.headerstambién se aplica a estos archivos, salvo las cabeceras que ya traen, comoCache-Control.