Skip to content

Commit

Permalink
feat: Cloudflare Pages _routes.json specification (#6441) (#6530)
Browse files Browse the repository at this point in the history
* feat: Cloudflare Pages _routes.json specification (#6441)
When a SvelteKit project is deployed to Cloudflare Pages, the server-side code is supported through Pages Functions (currently in beta). Unfortunately, by using Functions, each request must go through the server-side Functions code even if it doesn't need to. For instance, an immutable asset request to https://kit.svelte.dev/_app/immutable/assets/_layout-ab34ca4f.css would first have to route through Functions.

This is problematic since the request would "count" as a request to Functions even though only a static asset was served. Further, there is a slight amount of added latency.

This change exposes a set of includes and excludes based on static files generated.

* use writeFileSync over writeFile, for consistency with rest of codebase

* code style stuff

* tweak changeset

Co-authored-by: Rich Harris <[email protected]>
  • Loading branch information
jrf0110 and Rich-Harris authored Sep 21, 2022
1 parent afba48c commit ae8225d
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 4 deletions.
6 changes: 6 additions & 0 deletions .changeset/afraid-gifts-act.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@sveltejs/adapter-cloudflare': patch
'@sveltejs/kit': patch
---

Support Cloudflare Pages `_routes.json` specification
7 changes: 7 additions & 0 deletions packages/adapter-cloudflare/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,10 @@ import { Adapter } from '@sveltejs/kit';
import './ambient.js';

export default function plugin(): Adapter;

export interface RoutesJSONSpec {
version: 1;
description: string;
include: string[];
exclude: string[];
}
55 changes: 51 additions & 4 deletions packages/adapter-cloudflare/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,28 @@ export default function () {
builder.rimraf(tmp);
builder.mkdirp(tmp);

builder.writeClient(dest);
const written_files = builder.writeClient(dest);
builder.writePrerendered(dest);

const relativePath = posix.relative(tmp, builder.getServerDirectory());

builder.log.info(
`adapter-cloudfare is writing its own _headers file. If you have your own, you should duplicate the headers contained in: ${dest}/_headers`
);

writeFileSync(
`${tmp}/manifest.js`,
`export const manifest = ${builder.generateManifest({
relativePath
})};\n\nexport const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});\n`
`export const manifest = ${builder.generateManifest({ relativePath })};\n\n` +
`export const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});\n`
);

writeFileSync(
`${dest}/_routes.json`,
JSON.stringify(get_routes_json(builder.config.kit.appDir, written_files))
);

writeFileSync(`${dest}/_headers`, generate_headers(builder.config.kit.appDir));

builder.copy(`${files}/worker.js`, `${tmp}/_worker.js`, {
replace: {
SERVER: `${relativePath}/index.js`,
Expand All @@ -55,3 +65,40 @@ export default function () {
}
};
}

/**
* @param {string} app_dir
* @param {string[]} assets
* @returns {import('.').RoutesJSONSpec}
*/
function get_routes_json(app_dir, assets) {
return {
version: 1,
description: 'Generated by @sveltejs/adapter-cloudflare',
include: ['/*'],
exclude: [
`/${app_dir}/immutable/*`,
...assets
// We're being conservative by not excluding all assets in
// /static just yet. If there are any upstream auth rules to
// protect certain things (e.g. a PDF that requires auth),
// then we wouldn't want to prevent those requests from going
// to the user functions worker.
// We do want to show an example of a _routes.json that
// excludes more than just /_app/immutable/*, and favicons
// are a reasonable choice
.filter((filePath) => filePath.includes('favicon'))
]
};
}

/** @param {string} app_dir */
function generate_headers(app_dir) {
return `
# === START AUTOGENERATED SVELTE IMMUTABLE HEADERS ===
/${app_dir}/immutable/*
Cache-Control: public, immutable, max-age=31536000
X-Robots-Tag: noindex
# === END AUTOGENERATED SVELTE IMMUTABLE HEADERS ===
`.trim();
}

0 comments on commit ae8225d

Please sign in to comment.