From ef546ef806bf50a08331ca859d3999c36b3e5534 Mon Sep 17 00:00:00 2001 From: Sarah <144068104+iamawatermelo@users.noreply.github.com> Date: Tue, 29 Oct 2024 00:56:30 +0000 Subject: [PATCH 1/8] initial header work for prerendering --- .gitignore | 3 +- package-lock.json | 26 +-- package.json | 1 - src/routes/+layout.ts | 1 + src/routes/+page.js | 1 - src/routes/email/+page.server.ts | 2 + src/routes/email/subscribe/+page.server.ts | 2 + src/routes/email/unsubscribe/+page.server.ts | 2 + svelte.config.js | 2 +- vite.config.js | 27 --- vite.config.ts | 165 +++++++++++++++++++ 11 files changed, 181 insertions(+), 51 deletions(-) create mode 100644 src/routes/+layout.ts delete mode 100644 src/routes/+page.js delete mode 100644 vite.config.js create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore index 875f7df..aefc2eb 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ node_modules !.env.example vite.config.js.timestamp-* vite.config.ts.timestamp-* -.fonts \ No newline at end of file +.fonts +.wrangler \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4c61903..da6c737 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ }, "devDependencies": { "@poppanator/sveltekit-svg": "^5.0.0-svelte5.5", - "@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/adapter-cloudflare": "^4.7.2", "@sveltejs/kit": "^2.0.0", "@sveltejs/vite-plugin-svelte": "^4.0.0-next.6", @@ -1107,23 +1106,10 @@ "url": "https://ko-fi.com/killymxi" } }, - "node_modules/@sveltejs/adapter-auto": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.2.5.tgz", - "integrity": "sha512-27LR+uKccZ62lgq4N/hvyU2G+hTP9fxWEAfnZcl70HnyfAjMSsGk1z/SjAPXNCD1mVJIE7IFu3TQ8cQ/UH3c0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "import-meta-resolve": "^4.1.0" - }, - "peerDependencies": { - "@sveltejs/kit": "^2.0.0" - } - }, "node_modules/@sveltejs/adapter-cloudflare": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-cloudflare/-/adapter-cloudflare-4.7.3.tgz", - "integrity": "sha512-mHw0Jvd+74jj8fkduA8jrVXgsCY3+NwDc7FrDUiwU1Qe5QEuqPUab8Lv+np+4afEuMtFNytxUJsiiWlNN2w10w==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-cloudflare/-/adapter-cloudflare-4.7.4.tgz", + "integrity": "sha512-hKvWAfCQLzyNBunXEm5T+yyVfbQ+QNqnyqI0+lDoVYNQ58Yg/EPLEQIBS5aNpZgaEuBtY2tnegLsoPS8ZRcaIg==", "dev": true, "license": "MIT", "dependencies": { @@ -1137,9 +1123,9 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.7.1.tgz", - "integrity": "sha512-TBVnkwgYQT3EafGQK6Eyh5FlLEBlRhCmqPTwcdOs+QdnyUc3eCAxRWtXlFxIWtmk6pqv11zdng8qTpThdTogew==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.7.3.tgz", + "integrity": "sha512-Vx7nq5MJ86I8qXYsVidC5PX6xm+uxt8DydvOdmJoyOK7LvGP18OFEG359yY+aa51t6pENvqZAMqAREQQx1OI2Q==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/package.json b/package.json index 741cb2c..b1f0029 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ }, "devDependencies": { "@poppanator/sveltekit-svg": "^5.0.0-svelte5.5", - "@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/adapter-cloudflare": "^4.7.2", "@sveltejs/kit": "^2.0.0", "@sveltejs/vite-plugin-svelte": "^4.0.0-next.6", diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts new file mode 100644 index 0000000..c8cacf0 --- /dev/null +++ b/src/routes/+layout.ts @@ -0,0 +1 @@ +export const prerender = true; \ No newline at end of file diff --git a/src/routes/+page.js b/src/routes/+page.js deleted file mode 100644 index fe7cf72..0000000 --- a/src/routes/+page.js +++ /dev/null @@ -1 +0,0 @@ -// export const prerender = 'auto'; diff --git a/src/routes/email/+page.server.ts b/src/routes/email/+page.server.ts index e99f208..77c0c1d 100644 --- a/src/routes/email/+page.server.ts +++ b/src/routes/email/+page.server.ts @@ -7,6 +7,8 @@ import { createSubscribeToken } from '$lib/jwt'; import { sendEmail } from '$lib/emails/email'; import table from '$lib/airtable'; +export const prerender = false; + export const actions = { default: async ({ url, request }) => { const data = await request.formData(); diff --git a/src/routes/email/subscribe/+page.server.ts b/src/routes/email/subscribe/+page.server.ts index 6d961c5..b65b6e2 100644 --- a/src/routes/email/subscribe/+page.server.ts +++ b/src/routes/email/subscribe/+page.server.ts @@ -4,6 +4,8 @@ import { validateSubscribeToken } from '$lib/jwt'; import { redirect, type Actions } from '@sveltejs/kit'; import table from '$lib/airtable'; +export const prerender = false; + export const actions = { default: async ({ url }) => { const token = url.searchParams.get('token'); diff --git a/src/routes/email/unsubscribe/+page.server.ts b/src/routes/email/unsubscribe/+page.server.ts index 9c1c4f1..e32a60a 100644 --- a/src/routes/email/unsubscribe/+page.server.ts +++ b/src/routes/email/unsubscribe/+page.server.ts @@ -4,6 +4,8 @@ import { validateUnsubscribeToken } from '$lib/jwt'; import { redirect } from '@sveltejs/kit'; import table from '$lib/airtable'; +export const prerender = false; + export const load: PageServerLoad = async ({ url }) => { const token = url.searchParams.get('token'); diff --git a/svelte.config.js b/svelte.config.js index 8d76976..59ec9aa 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,4 +1,4 @@ -import adapter from '@sveltejs/adapter-auto'; +import adapter from '@sveltejs/adapter-cloudflare'; import { sveltePreprocess } from 'svelte-preprocess'; /** @type {import('@sveltejs/kit').Config} */ diff --git a/vite.config.js b/vite.config.js deleted file mode 100644 index 94a71f6..0000000 --- a/vite.config.js +++ /dev/null @@ -1,27 +0,0 @@ -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; -import svg from '@poppanator/sveltekit-svg'; - -export default defineConfig({ - plugins: [ - sveltekit(), - svg({ - svgoOptions: { - plugins: [ - { - name: 'preset-default', - params: { - overrides: { - removeViewBox: false // Why is this on by default!? - } - } - } - ] - } - }) - ], - build: { - cssMinify: 'lightningcss', - modulePreload: false - } -}); diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..8e3e6c6 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,165 @@ +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig, type Plugin, type ResolvedConfig } from 'vite'; +import svg from '@poppanator/sveltekit-svg'; + +let HEADERS = ` +* + Accept-CH: Width, Viewport-Width, Sec-CH-Width, Sec-CH-Viewport-Width, Sec-CH-Viewport-Height, Sec-CH-UA-Mobile +`.trim(); +let ROUTE_PATH = '/src/routes'; +let ALWAYS_PRELOADED_BUNDLED = [ + { + file: 'src/lib/fonts/DMSans.text.woff2', + as: 'font' + } +]; +let ALWAYS_PRELOADED_STATIC = [ + { + path: '/api/background.svg', + as: 'image' + } +]; + +let config: ResolvedConfig; +const plugin: Plugin = { + name: 'generate-headers', + + configResolved(resolvedConfig) { + console.log(resolvedConfig); + config = resolvedConfig; + }, + + async generateBundle(options, bundle, isWrite) { + let baseFsPath = config.root + ROUTE_PATH; + console.log(`Using base path ${baseFsPath}`); + + let fileToAssetMap: Record> = {}; + let pathToCssMap: Record> = {}; + + for (const chunk of Object.values(bundle)) { + if (chunk.type === 'asset') { + for (const name of chunk.originalFileNames) { + fileToAssetMap[name] = new Set([...(fileToAssetMap[name] || []), chunk.fileName]); + } + } + + if (chunk.type !== 'chunk' || !chunk.isDynamicEntry || !chunk.isEntry) { + continue; + } + + // Get CSS files + let cssFiles = new Set(); + chunk.viteMetadata?.importedCss?.forEach((file) => cssFiles.add(file)); + + for (const imported of chunk.imports) { + let importedChunk = bundle[imported]; + + if (importedChunk.type !== 'chunk') { + continue; + } + + importedChunk.viteMetadata?.importedCss?.forEach((file) => cssFiles.add(file)); + } + + // Get path + let path = null; + for (const alias of chunk.moduleIds) { + if (!alias.startsWith(baseFsPath)) { + continue; + } + + if (!alias.endsWith('/+page.svelte')) { + continue; + } + + path = alias.replace(baseFsPath, '').replace('+page.svelte', ''); + if (path !== '/') { + // Remove trailing slash like SvelteKit does + path = path.replace(/\/$/, ''); + } + } + + if (path === null) { + this.warn(`Failed to determine path for chunk ${chunk.fileName} (moduleIds: ${chunk.moduleIds})`); + continue; + } + + pathToCssMap[path] = cssFiles; + } + + let alwaysIncluded = [...ALWAYS_PRELOADED_STATIC]; + + for (const toResolve of ALWAYS_PRELOADED_BUNDLED) { + const resolved = fileToAssetMap[toResolve.file]; + if (resolved === undefined) { + console.log(fileToAssetMap); + return this.error(`Failed to resolve file ${toResolve.file}`); + } + + for (const file of resolved.keys()) { + alwaysIncluded.push({ + path: file, + as: toResolve.as + }); + } + } + + let headerOutput = `${HEADERS}\n\n# generated by generate-headers plugin`; + + for (const [path, files] of Object.entries(pathToCssMap)) { + headerOutput += `\n${path}\n Link: `; + const headers = [...alwaysIncluded]; + + for (const file of files) { + headers.push({ + path: file, + as: 'style' + }); + } + + headerOutput += headers + .map((v) => { + let header = `<${v.path}>; rel=preload; as=${v.as}`; + if (v.as === 'style') { + header += '; crossorigin'; + } + return header; + }) + .join(','); + headerOutput += '\n'; + } + + console.log(headerOutput); + + this.emitFile({ + type: 'asset', + fileName: '_headers', + source: headerOutput + }); + } +}; + +export default defineConfig({ + plugins: [ + sveltekit(), + svg({ + svgoOptions: { + plugins: [ + { + name: 'preset-default', + params: { + overrides: { + removeViewBox: false // Why is this on by default!? + } + } + } + ] + } + }), + plugin + ], + build: { + cssMinify: 'lightningcss', + modulePreload: false + } +}); From e98d319a23832ba5f0bbd322900fd4af4d1f9be6 Mon Sep 17 00:00:00 2001 From: Sarah <144068104+iamawatermelo@users.noreply.github.com> Date: Tue, 29 Oct 2024 01:03:21 +0000 Subject: [PATCH 2/8] oops --- .github/workflows/lighthouse.yml | 4 ---- vite.config.ts | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml index c0f0d3e..a70f7ee 100644 --- a/.github/workflows/lighthouse.yml +++ b/.github/workflows/lighthouse.yml @@ -14,10 +14,6 @@ jobs: run: | npm install npm run build - env: - AIRTABLE_BASE: ${{ secrets.AIRTABLE_BASE }} - AIRTABLE_TABLE: ${{ secrets.AIRTABLE_TABLE }} - AIRTABLE_TOKEN: ${{ secrets.AIRTABLE_TOKEN }} - name: run Lighthouse CI run: | npm install -g @lhci/cli@0.14.x diff --git a/vite.config.ts b/vite.config.ts index 8e3e6c6..cbf9f7f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,7 +3,7 @@ import { defineConfig, type Plugin, type ResolvedConfig } from 'vite'; import svg from '@poppanator/sveltekit-svg'; let HEADERS = ` -* +/* Accept-CH: Width, Viewport-Width, Sec-CH-Width, Sec-CH-Viewport-Width, Sec-CH-Viewport-Height, Sec-CH-UA-Mobile `.trim(); let ROUTE_PATH = '/src/routes'; @@ -121,7 +121,7 @@ const plugin: Plugin = { .map((v) => { let header = `<${v.path}>; rel=preload; as=${v.as}`; if (v.as === 'style') { - header += '; crossorigin'; + header += '; crossorigin=anonymous'; } return header; }) From 651565c676565293f1460dceee1c2fc4c8d685a4 Mon Sep 17 00:00:00 2001 From: Sarah <144068104+iamawatermelo@users.noreply.github.com> Date: Tue, 29 Oct 2024 01:11:56 +0000 Subject: [PATCH 3/8] i think that fixed it --- vite.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vite.config.ts b/vite.config.ts index cbf9f7f..91fa18d 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -120,9 +120,9 @@ const plugin: Plugin = { headerOutput += headers .map((v) => { let header = `<${v.path}>; rel=preload; as=${v.as}`; - if (v.as === 'style') { + // if (v.as === 'style') { header += '; crossorigin=anonymous'; - } + // } return header; }) .join(','); From b1d8ca89388ba557431b0be72bae37aff870dc59 Mon Sep 17 00:00:00 2001 From: Sarah <144068104+iamawatermelo@users.noreply.github.com> Date: Tue, 29 Oct 2024 01:16:17 +0000 Subject: [PATCH 4/8] tinker a bit more --- vite.config.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vite.config.ts b/vite.config.ts index 91fa18d..1b727db 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -119,10 +119,10 @@ const plugin: Plugin = { headerOutput += headers .map((v) => { - let header = `<${v.path}>; rel=preload; as=${v.as}`; - // if (v.as === 'style') { - header += '; crossorigin=anonymous'; - // } + let header = `<${v.path}>; rel="preload"; as="${v.as}"; nopush`; + if (v.as === 'font') { + header += '; crossorigin="anonymous"'; + } return header; }) .join(','); From 5601e7c9d0aaa9893fc19637df1d57208d17cd56 Mon Sep 17 00:00:00 2001 From: Sarah <144068104+iamawatermelo@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:47:19 +0000 Subject: [PATCH 5/8] preload +layout.svelte --- vite.config.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/vite.config.ts b/vite.config.ts index 1b727db..b87c6ab 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -35,6 +35,7 @@ const plugin: Plugin = { let fileToAssetMap: Record> = {}; let pathToCssMap: Record> = {}; + let layoutFiles: Set = new Set(); for (const chunk of Object.values(bundle)) { if (chunk.type === 'asset') { @@ -67,6 +68,11 @@ const plugin: Plugin = { if (!alias.startsWith(baseFsPath)) { continue; } + + if (alias.endsWith('/+layout.svelte')) { + cssFiles.forEach((file) => layoutFiles.add(file)); + break; + } if (!alias.endsWith('/+page.svelte')) { continue; @@ -103,7 +109,14 @@ const plugin: Plugin = { }); } } - + + for (const file of layoutFiles.keys()) { + alwaysIncluded.push({ + path: file, + as: 'style' + }) + } + let headerOutput = `${HEADERS}\n\n# generated by generate-headers plugin`; for (const [path, files] of Object.entries(pathToCssMap)) { From 5a5d0e37fccb7e947a32ed2db188cf9e44b30772 Mon Sep 17 00:00:00 2001 From: Sarah <144068104+iamawatermelo@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:59:01 +0000 Subject: [PATCH 6/8] disable JS preloading, again --- src/hooks.server.ts | 7 ++++++- vite.config.ts | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 685701d..3d61e6e 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -4,7 +4,12 @@ import type { Handle } from '@sveltejs/kit'; const PRELOADED_FONTS = [TextFontURL]; export const handle: Handle = async ({ event, resolve }) => { - const response = await resolve(event); + // Also disable JS preloading in prerendered files + const response = await resolve(event, { + preload({ type }) { + return type != 'js' && type != 'asset'; + } + }); // Disable JS preloading. This took hours to find. // I hate web development. diff --git a/vite.config.ts b/vite.config.ts index b87c6ab..39a8c91 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -173,6 +173,10 @@ export default defineConfig({ ], build: { cssMinify: 'lightningcss', - modulePreload: false + modulePreload: { + resolveDependencies(url, deps, context) { + return deps.filter((dep) => !dep.endsWith('.js')); + } + } } }); From a4286bdd52b93600b3d2df5e24cc61b3146e8991 Mon Sep 17 00:00:00 2001 From: Sarah <144068104+iamawatermelo@users.noreply.github.com> Date: Tue, 29 Oct 2024 12:10:18 +0000 Subject: [PATCH 7/8] increase cache time --- src/routes/api/background.svg/+server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/api/background.svg/+server.ts b/src/routes/api/background.svg/+server.ts index 54f074d..75895eb 100644 --- a/src/routes/api/background.svg/+server.ts +++ b/src/routes/api/background.svg/+server.ts @@ -77,7 +77,7 @@ export const GET = async ({ request }: { request: Request }) => { headers: { Vary: 'Width, Viewport-Width, Sec-CH-Width, Sec-CH-Viewport-Width, Sec-CH-Viewport-Height, Sec-CH-UA-Mobile', 'Content-Type': 'image/svg+xml', - 'Cache-Control': 'public, max-age=604800' + 'Cache-Control': 'immutable, max-age=31536000' } }); }; From 71d92cc842cb53b87dfc352510cc20ab2323fb67 Mon Sep 17 00:00:00 2001 From: Sarah <144068104+iamawatermelo@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:56:13 +0000 Subject: [PATCH 8/8] redeploy