From 4ae2d71a484d48f5c87e08e7e557bedfead08706 Mon Sep 17 00:00:00 2001 From: Luke Edwards Date: Fri, 25 Mar 2022 10:56:27 -0700 Subject: [PATCH 1/6] chore(cloudflare): optimize Cache usage; strict TS source --- packages/adapter-cloudflare/files/worker.js | 85 --------------------- packages/adapter-cloudflare/files/worker.ts | 74 ++++++++++++++++++ packages/adapter-cloudflare/index.js | 4 +- packages/adapter-cloudflare/package.json | 3 +- packages/adapter-cloudflare/tsconfig.json | 2 +- pnpm-lock.yaml | 16 +++- 6 files changed, 94 insertions(+), 90 deletions(-) delete mode 100644 packages/adapter-cloudflare/files/worker.js create mode 100644 packages/adapter-cloudflare/files/worker.ts diff --git a/packages/adapter-cloudflare/files/worker.js b/packages/adapter-cloudflare/files/worker.js deleted file mode 100644 index 8a56e6a544db..000000000000 --- a/packages/adapter-cloudflare/files/worker.js +++ /dev/null @@ -1,85 +0,0 @@ -import { Server } from 'SERVER'; -import { manifest, prerendered } from 'MANIFEST'; - -const server = new Server(manifest); - -const prefix = `/${manifest.appDir}/`; - -export default { - /** - * @param {Request} req - * @param {any} env - * @param {any} context - */ - async fetch(req, env, context) { - const url = new URL(req.url); - - // static assets - if (url.pathname.startsWith(prefix)) { - /** @type {Response} */ - const res = await env.ASSETS.fetch(req); - - return new Response(res.body, { - headers: { - // include original cache headers, minus cache-control which - // is overridden, and etag which is no longer useful - 'cache-control': 'public, immutable, max-age=31536000', - 'content-type': res.headers.get('content-type'), - 'x-robots-tag': 'noindex' - } - }); - } - - // prerendered pages and index.html files - const pathname = url.pathname.replace(/\/$/, ''); - let file = pathname.substring(1); - - try { - file = decodeURIComponent(file); - } catch (err) { - // ignore - } - - if ( - manifest.assets.has(file) || - manifest.assets.has(file + '/index.html') || - prerendered.has(pathname || '/') - ) { - return env.ASSETS.fetch(req); - } - - // dynamically-generated pages - try { - // @ts-expect-error - `default` exists only in the cloudflare workers environment - const cache = caches.default; - let response = await cache.match(req); - - if (!response) { - response = await server.respond(req, { - platform: { env, context }, - getClientAddress() { - return req.headers.get('cf-connecting-ip'); - } - }); - - // Use waitUntil so you can return the response without blocking on - // writing to cache - try { - // If cookies are being set, ensure we dont cache the page. - if (response.headers.has('Set-Cookie')) { - response = new Response(response.body, response); - response.headers.append('Cache-Control', 'private=Set-Cookie'); - } - - context.waitUntil(cache.put(req, response.clone())); - } catch { - // noop - } - } - - return response; - } catch (e) { - return new Response('Error rendering route: ' + (e.message || e.toString()), { status: 500 }); - } - } -}; diff --git a/packages/adapter-cloudflare/files/worker.ts b/packages/adapter-cloudflare/files/worker.ts new file mode 100644 index 000000000000..0daae44e281c --- /dev/null +++ b/packages/adapter-cloudflare/files/worker.ts @@ -0,0 +1,74 @@ +import { Server } from 'SERVER'; +import { manifest, prerendered } from 'MANIFEST'; +import * as Cache from 'worktop/cfw.cache'; + +import type { Module, Bindings } from 'worktop/cfw'; +import type { Durable } from 'worktop/cfw.durable'; + +interface Environment extends Bindings { + ASSETS: Durable.Object; +} + +const server = new Server(manifest); + +const prefix = `/${manifest.appDir}/`; + +const worker: Module.Worker = { + async fetch(req, env, context) { + try { + let res = await Cache.lookup(req); + if (res) return res; + + let { pathname } = new URL(req.url); + + // static assets + if (pathname.startsWith(prefix)) { + res = await env.ASSETS.fetch(req); + + res = new Response(res.body, { + headers: { + // include original cache headers, minus cache-control which + // is overridden, and etag which is no longer useful + 'cache-control': 'public, immutable, max-age=31536000', + 'content-type': res.headers.get('content-type'), + 'x-robots-tag': 'noindex' + } + }); + } else { + // prerendered pages and index.html files + pathname = pathname.replace(/\/$/, '') || '/'; + + let file = pathname.substring(1); + + try { + file = decodeURIComponent(file); + } catch (err) { + // ignore + } + + if ( + manifest.assets.has(file) || + manifest.assets.has(file + '/index.html') || + prerendered.has(pathname) + ) { + res = await env.ASSETS.fetch(req); + } else { + // dynamically-generated pages + res = await server.respond(req, { + platform: { env, context }, + getClientAddress() { + return req.headers.get('cf-connecting-ip'); + } + }); + } + } + + // Writes to Cache only if allowed + return Cache.save(req, res, context); + } catch (e) { + return new Response('Error rendering route: ' + (e.message || e.toString()), { status: 500 }); + } + } +}; + +export default worker; diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index d79e65807257..f284cd9fac03 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -29,7 +29,7 @@ export default function (options = {}) { })};\n\nexport const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});\n` ); - builder.copy(`${files}/worker.js`, `${tmp}/_worker.js`, { + builder.copy(`${files}/worker.ts`, `${tmp}/_worker.ts`, { replace: { SERVER: `${relativePath}/index.js`, MANIFEST: './manifest.js' @@ -40,7 +40,7 @@ export default function (options = {}) { target: 'es2020', platform: 'browser', ...options, - entryPoints: [`${tmp}/_worker.js`], + entryPoints: [`${tmp}/_worker.ts`], outfile: `${dest}/_worker.js`, allowOverwrite: true, format: 'esm', diff --git a/packages/adapter-cloudflare/package.json b/packages/adapter-cloudflare/package.json index b12a8a30f774..31df1c52c05f 100644 --- a/packages/adapter-cloudflare/package.json +++ b/packages/adapter-cloudflare/package.json @@ -29,7 +29,8 @@ "check-format": "prettier --check . --config ../../.prettierrc --ignore-path .gitignore" }, "dependencies": { - "esbuild": "^0.14.21" + "esbuild": "^0.14.21", + "worktop": "0.8.0-next.12" }, "devDependencies": { "typescript": "^4.6.2" diff --git a/packages/adapter-cloudflare/tsconfig.json b/packages/adapter-cloudflare/tsconfig.json index 87628b965a0a..502209d0b668 100644 --- a/packages/adapter-cloudflare/tsconfig.json +++ b/packages/adapter-cloudflare/tsconfig.json @@ -11,5 +11,5 @@ "@sveltejs/kit": ["../kit/types/index"] } }, - "include": ["**/*.js", "ambient.d.ts"] + "include": ["**/*.js", "ambient.d.ts", "files/worker.ts"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dc732d636efe..3d34da5568cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,8 +71,10 @@ importers: specifiers: esbuild: ^0.14.21 typescript: ^4.6.2 + worktop: 0.8.0-next.12 dependencies: esbuild: 0.14.21 + worktop: 0.8.0-next.12 devDependencies: typescript: 4.6.2 @@ -4341,7 +4343,6 @@ packages: /mrmime/1.0.0: resolution: {integrity: sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==} engines: {node: '>=10'} - dev: true /ms/2.0.0: resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=} @@ -5042,6 +5043,11 @@ packages: engines: {node: '>=6'} dev: true + /regexparam/2.0.0: + resolution: {integrity: sha512-gJKwd2MVPWHAIFLsaYDZfyKzHNS4o7E/v8YmNf44vmeV2e4YfVoDToTOKTvE7ab68cRJ++kLuEXJBaEeJVt5ow==} + engines: {node: '>=8'} + dev: false + /regexpp/3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} @@ -6095,6 +6101,14 @@ packages: engines: {node: '>=0.10.0'} dev: true + /worktop/0.8.0-next.12: + resolution: {integrity: sha512-ZXdgI9XOf0uB4IegFoViLdQ0Bf7hish0XMHwuV3nopOXygfLJkwAC5+HyA+sihBMSM2sLLQ5uGnD5aknL8+NQg==} + engines: {node: '>=12'} + dependencies: + mrmime: 1.0.0 + regexparam: 2.0.0 + dev: false + /wrap-ansi/6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} From 5c15feeb2364957198683a718aeeb08482e55cbc Mon Sep 17 00:00:00 2001 From: Luke Edwards Date: Fri, 25 Mar 2022 11:54:53 -0700 Subject: [PATCH 2/6] chore: add changeset --- .changeset/empty-falcons-run.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/empty-falcons-run.md diff --git a/.changeset/empty-falcons-run.md b/.changeset/empty-falcons-run.md new file mode 100644 index 000000000000..803f03c51d06 --- /dev/null +++ b/.changeset/empty-falcons-run.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-cloudflare': patch +--- + +Convert entry to TypeScript; check for Cache match sooner; use `worktop` for types & Cache operations From 2ce5407b94ec6adc17beaf46e1e77673bdadea4d Mon Sep 17 00:00:00 2001 From: Luke Edwards Date: Mon, 28 Mar 2022 10:45:14 -0700 Subject: [PATCH 3/6] skip lib check for conflicts --- packages/adapter-cloudflare/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapter-cloudflare/package.json b/packages/adapter-cloudflare/package.json index 31df1c52c05f..f29a01cdda2f 100644 --- a/packages/adapter-cloudflare/package.json +++ b/packages/adapter-cloudflare/package.json @@ -25,7 +25,7 @@ "scripts": { "lint": "eslint --ignore-path .gitignore \"**/*.{ts,js,svelte}\" && npm run check-format", "format": "npm run check-format -- --write", - "check": "tsc", + "check": "tsc --skipLibCheck", "check-format": "prettier --check . --config ../../.prettierrc --ignore-path .gitignore" }, "dependencies": { From 77702f90db0faf8d5d16556af7cd4e198423729f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 31 Mar 2022 13:06:14 -0400 Subject: [PATCH 4/6] bundle worktop (#4473) * bundle worktop * build on prepublishOnly * Update packages/adapter-cloudflare/tsconfig.json * update builder file paths Co-authored-by: Luke Edwards --- packages/adapter-cloudflare/.gitignore | 4 +--- packages/adapter-cloudflare/index.js | 4 ++-- packages/adapter-cloudflare/package.json | 4 +++- packages/adapter-cloudflare/{files => src}/worker.ts | 0 packages/adapter-cloudflare/tsconfig.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) rename packages/adapter-cloudflare/{files => src}/worker.ts (100%) diff --git a/packages/adapter-cloudflare/.gitignore b/packages/adapter-cloudflare/.gitignore index e87415077413..beb15cd7fa9a 100644 --- a/packages/adapter-cloudflare/.gitignore +++ b/packages/adapter-cloudflare/.gitignore @@ -1,3 +1 @@ -.DS_Store -node_modules -target \ No newline at end of file +/files \ No newline at end of file diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index f284cd9fac03..d79e65807257 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -29,7 +29,7 @@ export default function (options = {}) { })};\n\nexport const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});\n` ); - builder.copy(`${files}/worker.ts`, `${tmp}/_worker.ts`, { + builder.copy(`${files}/worker.js`, `${tmp}/_worker.js`, { replace: { SERVER: `${relativePath}/index.js`, MANIFEST: './manifest.js' @@ -40,7 +40,7 @@ export default function (options = {}) { target: 'es2020', platform: 'browser', ...options, - entryPoints: [`${tmp}/_worker.ts`], + entryPoints: [`${tmp}/_worker.js`], outfile: `${dest}/_worker.js`, allowOverwrite: true, format: 'esm', diff --git a/packages/adapter-cloudflare/package.json b/packages/adapter-cloudflare/package.json index f29a01cdda2f..245cf859ec6d 100644 --- a/packages/adapter-cloudflare/package.json +++ b/packages/adapter-cloudflare/package.json @@ -23,10 +23,12 @@ ], "main": "index.js", "scripts": { + "build": "esbuild src/worker.ts --bundle --outfile=files/worker.js --external:SERVER --external:MANIFEST --format=esm", "lint": "eslint --ignore-path .gitignore \"**/*.{ts,js,svelte}\" && npm run check-format", "format": "npm run check-format -- --write", "check": "tsc --skipLibCheck", - "check-format": "prettier --check . --config ../../.prettierrc --ignore-path .gitignore" + "check-format": "prettier --check . --config ../../.prettierrc --ignore-path .gitignore", + "prepublishOnly": "npm run build" }, "dependencies": { "esbuild": "^0.14.21", diff --git a/packages/adapter-cloudflare/files/worker.ts b/packages/adapter-cloudflare/src/worker.ts similarity index 100% rename from packages/adapter-cloudflare/files/worker.ts rename to packages/adapter-cloudflare/src/worker.ts diff --git a/packages/adapter-cloudflare/tsconfig.json b/packages/adapter-cloudflare/tsconfig.json index 502209d0b668..d90692441a52 100644 --- a/packages/adapter-cloudflare/tsconfig.json +++ b/packages/adapter-cloudflare/tsconfig.json @@ -11,5 +11,5 @@ "@sveltejs/kit": ["../kit/types/index"] } }, - "include": ["**/*.js", "ambient.d.ts", "files/worker.ts"] + "include": ["index.js", "ambient.d.ts", "src/worker.ts"] } From 0185508b09a08ae56c4ec0f691875c981baf823c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 31 Mar 2022 14:21:34 -0400 Subject: [PATCH 5/6] convert to JS (#4474) --- packages/adapter-cloudflare/package.json | 2 +- .../adapter-cloudflare/src/{worker.ts => worker.js} | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) rename packages/adapter-cloudflare/src/{worker.ts => worker.js} (88%) diff --git a/packages/adapter-cloudflare/package.json b/packages/adapter-cloudflare/package.json index 245cf859ec6d..ed8bb64ac727 100644 --- a/packages/adapter-cloudflare/package.json +++ b/packages/adapter-cloudflare/package.json @@ -23,7 +23,7 @@ ], "main": "index.js", "scripts": { - "build": "esbuild src/worker.ts --bundle --outfile=files/worker.js --external:SERVER --external:MANIFEST --format=esm", + "build": "esbuild src/worker.js --bundle --outfile=files/worker.js --external:SERVER --external:MANIFEST --format=esm", "lint": "eslint --ignore-path .gitignore \"**/*.{ts,js,svelte}\" && npm run check-format", "format": "npm run check-format -- --write", "check": "tsc --skipLibCheck", diff --git a/packages/adapter-cloudflare/src/worker.ts b/packages/adapter-cloudflare/src/worker.js similarity index 88% rename from packages/adapter-cloudflare/src/worker.ts rename to packages/adapter-cloudflare/src/worker.js index 0daae44e281c..dbb8f31c3bae 100644 --- a/packages/adapter-cloudflare/src/worker.ts +++ b/packages/adapter-cloudflare/src/worker.js @@ -2,18 +2,12 @@ import { Server } from 'SERVER'; import { manifest, prerendered } from 'MANIFEST'; import * as Cache from 'worktop/cfw.cache'; -import type { Module, Bindings } from 'worktop/cfw'; -import type { Durable } from 'worktop/cfw.durable'; - -interface Environment extends Bindings { - ASSETS: Durable.Object; -} - const server = new Server(manifest); const prefix = `/${manifest.appDir}/`; -const worker: Module.Worker = { +/** @type {import('worktop/cfw').Module.Worker<{ ASSETS: import('worktop/cfw.durable').Durable.Object }>} */ +const worker = { async fetch(req, env, context) { try { let res = await Cache.lookup(req); From c0724b20a6b59f49d29307162760a4f092c94284 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 31 Mar 2022 14:22:10 -0400 Subject: [PATCH 6/6] Update .changeset/empty-falcons-run.md --- .changeset/empty-falcons-run.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/empty-falcons-run.md b/.changeset/empty-falcons-run.md index 803f03c51d06..9f3ff43f014c 100644 --- a/.changeset/empty-falcons-run.md +++ b/.changeset/empty-falcons-run.md @@ -2,4 +2,4 @@ '@sveltejs/adapter-cloudflare': patch --- -Convert entry to TypeScript; check for Cache match sooner; use `worktop` for types & Cache operations +Check for Cache match sooner; use `worktop` for types & Cache operations