diff --git a/packages/adapter-cloudflare-workers/README.md b/packages/adapter-cloudflare-workers/README.md index 3b1820f4c521..bae025b869a5 100644 --- a/packages/adapter-cloudflare-workers/README.md +++ b/packages/adapter-cloudflare-workers/README.md @@ -22,6 +22,13 @@ bucket = "./build" entry-point = "./workers-site" ``` +The adapter accepts the following configuration properties: +| property | default | description | +|---|---|---| +| `pageCacheTTL` | `null` | Sets `cache-control` `max-age` for rendered responses if not defined. WARNING: this will apply to all page/request routes, disabled by default for security reasons. | +| `staticCacheTTL` | `60 * 60 * 24 * 90` (90 days) | Sets `cache-control` `max-age` for static assets. | +| `edgeCacheTTL` | `60 * 60 * 24 * 90` (90 days) | Sets CloudFlare Edge Cache TTL for static assets. | + It's recommended that you add the `build` and `workers-site` folders (or whichever other folders you specify) to your `.gitignore`. More info on configuring a cloudflare worker site can be found [here](https://developers.cloudflare.com/workers/platform/sites/start-from-existing) diff --git a/packages/adapter-cloudflare-workers/files/entry.js b/packages/adapter-cloudflare-workers/files/entry.js index d5749d7f83cb..fcd937dd209e 100644 --- a/packages/adapter-cloudflare-workers/files/entry.js +++ b/packages/adapter-cloudflare-workers/files/entry.js @@ -7,12 +7,28 @@ addEventListener('fetch', (event) => { }); async function handle(event) { + // fall back to an app route + const request = event.request; + const request_url = new URL(request.url); + // try static files first - if (event.request.method == 'GET') { + if (event.request.method == 'GET' && /\/.+\..+$/.test(request_url.pathname)) { try { + // TODO add per-asset/page options for cache + // use defaults for bot files (2d edge cache) + if (/sitemap.*\.xml$|robots.txt$/.test(request_url.pathname)) { + return await getAssetFromKV(event); + } // TODO rather than attempting to get an asset, // use the asset manifest to see if it exists - return await getAssetFromKV(event); + return await getAssetFromKV(event, { + cacheControl: { + // eslint-disable-next-line no-undef + browserTTL: STATIC_CACHE_TTL, + // eslint-disable-next-line no-undef + edgeTTL: EDGE_CACHE_TTL + } + }); } catch (e) { if (!(e instanceof NotFoundError)) { return new Response('Error loading static asset:' + (e.message || e.toString()), { @@ -22,10 +38,6 @@ async function handle(event) { } } - // fall back to an app route - const request = event.request; - const request_url = new URL(request.url); - try { const rendered = await render({ host: request_url.host, @@ -37,6 +49,13 @@ async function handle(event) { }); if (rendered) { + const { headers } = rendered; + // inject cache-control header + // eslint-disable-next-line no-undef + if (!!PAGE_CACHE_TTL && !(headers['Cache-Control'] || headers['cache-control'])) { + // eslint-disable-next-line no-undef + rendered.headers['cache-control'] = `max-age=${PAGE_CACHE_TTL}`; + } return new Response(rendered.body, { status: rendered.status, headers: rendered.headers diff --git a/packages/adapter-cloudflare-workers/index.js b/packages/adapter-cloudflare-workers/index.js index 856d162d3f27..4b57648153c2 100644 --- a/packages/adapter-cloudflare-workers/index.js +++ b/packages/adapter-cloudflare-workers/index.js @@ -4,7 +4,7 @@ import esbuild from 'esbuild'; import toml from '@iarna/toml'; import { fileURLToPath } from 'url'; -export default function () { +export default function (options = {}) { /** @type {import('@sveltejs/kit').Adapter} */ const adapter = { name: '@sveltejs/adapter-cloudflare-workers', @@ -29,12 +29,22 @@ export default function () { utils.log.minor('Generating worker...'); utils.copy(`${files}/entry.js`, '.svelte-kit/cloudflare-workers/entry.js'); + const { + pageCacheTTL = null, + staticCacheTTL = 60 * 60 * 24 * 90, // 90 days + edgeCacheTTL = 60 * 60 * 24 * 90 // 90 days + } = options; await esbuild.build({ entryPoints: ['.svelte-kit/cloudflare-workers/entry.js'], outfile: `${entrypoint}/index.js`, bundle: true, target: 'es2020', - platform: 'node' // TODO would be great if we could generate ESM and use type = "javascript" + platform: 'node', // TODO would be great if we could generate ESM and use type = "javascript" + define: { + PAGE_CACHE_TTL: pageCacheTTL, + STATIC_CACHE_TTL: staticCacheTTL, + EDGE_CACHE_TTL: edgeCacheTTL + } }); fs.writeFileSync(`${entrypoint}/package.json`, JSON.stringify({ main: 'index.js' }));