From d5d482e93e02240ad6fb48b2db6e249c58d1b085 Mon Sep 17 00:00:00 2001 From: dev <> Date: Tue, 7 Nov 2023 07:12:08 +0000 Subject: [PATCH] blog: Use Cloudflare KV to store assets --- phoenix-blog/{src => }/public/favicon.ico | Bin phoenix-blog/{src => }/public/robots.txt | 0 ...ca4c37898bca4ff1a357cf7c481dfe0375b737.css | 0 phoenix-blog/src/caching.ts | 11 -------- phoenix-blog/src/index.ts | 16 +++++++----- phoenix-blog/src/routes/favicon.ts | 17 ------------- phoenix-blog/src/routes/indexcss.ts | 17 ------------- phoenix-blog/src/routes/public.ts | 24 ++++++++++++++++++ phoenix-blog/src/routes/robotstxt.ts | 13 ---------- phoenix-blog/wrangler.toml | 3 +++ 10 files changed, 37 insertions(+), 64 deletions(-) rename phoenix-blog/{src => }/public/favicon.ico (100%) rename phoenix-blog/{src => }/public/robots.txt (100%) rename phoenix-blog/{src => }/public/theme/index-5eca4c37898bca4ff1a357cf7c481dfe0375b737.css (100%) delete mode 100644 phoenix-blog/src/routes/favicon.ts delete mode 100644 phoenix-blog/src/routes/indexcss.ts create mode 100644 phoenix-blog/src/routes/public.ts delete mode 100644 phoenix-blog/src/routes/robotstxt.ts diff --git a/phoenix-blog/src/public/favicon.ico b/phoenix-blog/public/favicon.ico similarity index 100% rename from phoenix-blog/src/public/favicon.ico rename to phoenix-blog/public/favicon.ico diff --git a/phoenix-blog/src/public/robots.txt b/phoenix-blog/public/robots.txt similarity index 100% rename from phoenix-blog/src/public/robots.txt rename to phoenix-blog/public/robots.txt diff --git a/phoenix-blog/src/public/theme/index-5eca4c37898bca4ff1a357cf7c481dfe0375b737.css b/phoenix-blog/public/theme/index-5eca4c37898bca4ff1a357cf7c481dfe0375b737.css similarity index 100% rename from phoenix-blog/src/public/theme/index-5eca4c37898bca4ff1a357cf7c481dfe0375b737.css rename to phoenix-blog/public/theme/index-5eca4c37898bca4ff1a357cf7c481dfe0375b737.css diff --git a/phoenix-blog/src/caching.ts b/phoenix-blog/src/caching.ts index cf254f3..e0e2389 100644 --- a/phoenix-blog/src/caching.ts +++ b/phoenix-blog/src/caching.ts @@ -1,17 +1,6 @@ import { sha256Sum } from "@phoenix/core/crypto"; import { Context } from "./context"; -let etagsCache = new Map(); - -export async function getEtag(path: string, content: string): Promise { - let etag = etagsCache.get(path); - if (!etag) { - etag = await sha256Sum(content); - etagsCache.set(path, etag); - } - return etag; -} - export function handleCaching(ctx: Context, cacheControl: string, etag: string): Response | null { ctx.res.headers.set('Cache-Control', cacheControl); ctx.res.headers.set('ETag', `"${etag}"`); diff --git a/phoenix-blog/src/index.ts b/phoenix-blog/src/index.ts index 66bd0d6..d0520e4 100644 --- a/phoenix-blog/src/index.ts +++ b/phoenix-blog/src/index.ts @@ -2,23 +2,27 @@ import { Hono } from 'hono'; import { NotFoundError } from '@phoenix/core/errors'; import { ErrorTemplate } from './routes/_error'; import { Bindings, Variables } from './context'; -import { robotsTxt } from './routes/robotstxt'; -import { favicon } from './routes/favicon'; -import { indexCss } from './routes/indexcss'; import { handlebars } from './routes/handlebars'; import { index } from './routes'; import { page } from './routes/page'; +import { publicCacheControl, serveFavicon, serveRobotsTxt, serveTheme } from './routes/public'; +import { etag } from 'hono/etag' const app = new Hono<{ Bindings: Bindings; Variables: Variables }>(); +const staticAssets = new Hono<{ Bindings: Bindings; Variables: Variables }>(); app.use('*', async (ctx, next) => { ctx.res.headers.set('X-Robots-Tag', 'noindex'); await next(); }) -app.get('/robots.txt', robotsTxt); -app.get('/favicon.ico', favicon); -app.get('/theme/index-5eca4c37898bca4ff1a357cf7c481dfe0375b737.css', indexCss); +staticAssets.use('*', etag()); +staticAssets.use('*', publicCacheControl); +staticAssets.get('/robots.txt', etag(), serveRobotsTxt); +staticAssets.get('/favicon.ico', serveFavicon); +staticAssets.get('/theme/*', serveTheme); + +app.route('/', staticAssets); app.get('/handlebars', handlebars); app.get('/', index); diff --git a/phoenix-blog/src/routes/favicon.ts b/phoenix-blog/src/routes/favicon.ts deleted file mode 100644 index 0504603..0000000 --- a/phoenix-blog/src/routes/favicon.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Context } from "../context"; -import { getEtag, handleCaching } from "../caching"; -import faviconFileContent from '../public/favicon.ico'; - -export async function favicon(ctx: Context): Promise { - let etag = await getEtag('/favicon.ico', '/favicon.ico'); - const cacheHit = handleCaching(ctx, 'public, max-age=3600, must-revalidate', etag); - if (cacheHit) { - return cacheHit; - } - - return new Response(faviconFileContent, { - headers: { - 'Content-Type': 'image/x-icon', - }, - }) -} diff --git a/phoenix-blog/src/routes/indexcss.ts b/phoenix-blog/src/routes/indexcss.ts deleted file mode 100644 index 6330ba5..0000000 --- a/phoenix-blog/src/routes/indexcss.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { getEtag, handleCaching } from "../caching"; -import { Context } from "../context"; -import indexCssFielContent from '../public/theme/index-5eca4c37898bca4ff1a357cf7c481dfe0375b737.css'; - -export async function indexCss(ctx: Context): Promise { - let etag = await getEtag('/theme/index-5eca4c37898bca4ff1a357cf7c481dfe0375b737.css', indexCssFielContent); - const cacheHit = handleCaching(ctx, 'public, max-age=31536000, immutable', etag); - if (cacheHit) { - return cacheHit; - } - - return new Response(indexCssFielContent, { - headers: { - 'Content-Type': 'text/css; charset=utf-8', - }, - }) -} diff --git a/phoenix-blog/src/routes/public.ts b/phoenix-blog/src/routes/public.ts new file mode 100644 index 0000000..d1ad00a --- /dev/null +++ b/phoenix-blog/src/routes/public.ts @@ -0,0 +1,24 @@ +import { Context, Next } from 'hono'; +import { serveStatic } from 'hono/cloudflare-workers'; + +export const serveFavicon = serveStatic({ path: './favicon.ico' }); +export const serveRobotsTxt = serveStatic({ path: './robots.txt' }); +export const serveTheme = serveStatic(); + +export async function publicCacheControl(ctx: Context, next: Next) { + const url = new URL(ctx.req.url); + switch (url.pathname) { + case '/favicon.ico': + ctx.res.headers.set('Cache-Control', 'public, max-age=3600, must-revalidate'); + break; + default: { + if (url.pathname.startsWith('/theme')) { + ctx.res.headers.set('Cache-Control', 'public, max-age=31536000, immutable'); + } else { + ctx.res.headers.set('Cache-Control', 'public, max-age=1800, immutable'); + } + break; + } + } + await next(); +} diff --git a/phoenix-blog/src/routes/robotstxt.ts b/phoenix-blog/src/routes/robotstxt.ts deleted file mode 100644 index ab09a1e..0000000 --- a/phoenix-blog/src/routes/robotstxt.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { getEtag, handleCaching } from "../caching"; -import { Context } from "../context"; -import robotsTxtFileContent from '../public/robots.txt'; - -export async function robotsTxt(ctx: Context): Promise { - let etag = await getEtag('/robots.txt', robotsTxtFileContent); - const cacheHit = handleCaching(ctx, 'public, max-age=1800, must-revalidate', etag); - if (cacheHit) { - return cacheHit; - } - - return ctx.text(robotsTxtFileContent); -}; diff --git a/phoenix-blog/wrangler.toml b/phoenix-blog/wrangler.toml index 47b53b0..2ddcdab 100644 --- a/phoenix-blog/wrangler.toml +++ b/phoenix-blog/wrangler.toml @@ -6,6 +6,9 @@ services = [ { binding = "api", service = "phoenix-api" } ] +[site] +bucket = "./public" + # See https://developers.cloudflare.com/workers/wrangler/bundling/ # and https://developers.cloudflare.com/workers/wrangler/configuration/#bundling rules = [