perf: emit static asset cache headers

This commit is contained in:
Peter Steinberger 2026-05-07 01:22:46 +01:00
parent 8d2d8b3a52
commit 77deb8bba4
No known key found for this signature in database
3 changed files with 34 additions and 0 deletions

View File

@ -35,6 +35,11 @@ Production is still on the safe Worker Static Assets fallback until the Cloudfla
- Header: `X-OpenClaw-Docs-Origin: cloudflare-static-assets`
- Cache-Control follows the same policy as the R2 manifest.
The fallback uses two cache mechanisms:
- `workers/docs-router.ts` sets headers for slashless docs pages and `Accept: text/markdown` responses because those paths run through Worker code.
- `scripts/docs-site/cloudflare-prune.mjs` writes `dist/docs-site/_headers` so direct asset-first paths like `/assets/docs-site.css`, `/concepts/models.md`, and `/llms-full.txt` get the same cache policy without forcing all traffic through Worker code.
The fallback exists because the Services@openclaw.org Cloudflare token currently cannot access R2. Local verification against account `91b59577e757131d68d55a471fe32aca` fails before bucket operations with Cloudflare API auth error `10000`.
Do not remove the Worker route or switch `.github/workflows/pages.yml` to R2-only until R2 access is fixed and the R2 workflow has completed successfully.

View File

@ -16,6 +16,7 @@ if (!fs.existsSync(site)) throw new Error("dist/docs-site does not exist; run do
removeJunkFiles(site);
removeLocalizedMarkdown(site);
rebuildEnglishSearch();
writeStaticAssetHeaders();
const fileCount = countFiles(site);
if (fileCount > cloudflareFreeFileLimit) {
@ -67,6 +68,32 @@ function rebuildEnglishSearch() {
if (result.status !== 0) throw new Error(`pagefind failed with status ${result.status ?? "unknown"}`);
}
function writeStaticAssetHeaders() {
fs.writeFileSync(path.join(site, "_headers"), [
"/assets/*",
" Cache-Control: public, max-age=31536000, immutable",
"",
"/pagefind/*",
" Cache-Control: public, max-age=31536000, immutable",
"",
"/*.html",
" Cache-Control: public, max-age=60, s-maxage=86400, stale-while-revalidate=604800",
"",
"/*.md",
" Cache-Control: public, max-age=300, s-maxage=3600, stale-while-revalidate=86400",
"",
"/*.txt",
" Cache-Control: public, max-age=300, s-maxage=3600, stale-while-revalidate=86400",
"",
"/*.json",
" Cache-Control: public, max-age=300, s-maxage=3600, stale-while-revalidate=86400",
"",
"/*.jsonl",
" Cache-Control: public, max-age=300, s-maxage=3600, stale-while-revalidate=86400",
"",
].join("\n"));
}
function linkOrCopy(from, to) {
fs.mkdirSync(path.dirname(to), { recursive: true });
try {

View File

@ -16,11 +16,13 @@ copyTree(sourceDir, outputDir);
const entries = [];
for (const file of walk(outputDir)) {
const key = toKey(path.relative(outputDir, file));
if (key === "_headers") continue;
entries.push(entryFor(key, file, key));
}
for (const file of walk(outputDir)) {
const rel = toKey(path.relative(outputDir, file));
if (rel === "_headers") continue;
if (!rel.endsWith("/index.html") || rel === "index.html") continue;
const slashlessKey = rel.slice(0, -"/index.html".length);
entries.push(entryFor(slashlessKey, file, rel));