diff --git a/.changeset/healthy-singers-stare.md b/.changeset/healthy-singers-stare.md new file mode 100644 index 000000000000..43bc2b42887b --- /dev/null +++ b/.changeset/healthy-singers-stare.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-vercel': patch +--- + +[fix] only apply immutable cache-control headers to immutable assets diff --git a/.changeset/old-chicken-cough.md b/.changeset/old-chicken-cough.md new file mode 100644 index 000000000000..b3aae3fb3035 --- /dev/null +++ b/.changeset/old-chicken-cough.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-static': patch +--- + +[fix] match `adapter-vercel` logic for serving prerendered content diff --git a/packages/adapter-static/index.js b/packages/adapter-static/index.js index b43956ae2938..8f859dabcd8e 100644 --- a/packages/adapter-static/index.js +++ b/packages/adapter-static/index.js @@ -71,9 +71,7 @@ See https://kit.svelte.dev/docs/page-options#prerender for more details` assets = pages, fallback, precompress - } = options ?? - platform?.defaults(builder.config) ?? - /** @type {import('./index').AdapterOptions} */ ({}); + } = options ?? platform?.defaults ?? /** @type {import('./index').AdapterOptions} */ ({}); builder.rimraf(assets); builder.rimraf(pages); diff --git a/packages/adapter-static/platforms.js b/packages/adapter-static/platforms.js index d92967d09a3c..3ecf37cb30d1 100644 --- a/packages/adapter-static/platforms.js +++ b/packages/adapter-static/platforms.js @@ -4,26 +4,22 @@ import fs from 'fs'; * @typedef {{ * name: string; * test: () => boolean; - * defaults: (config: any) => import('./index').AdapterOptions; // TODO + * defaults: import('./index').AdapterOptions; * done: (builder: import('@sveltejs/kit').Builder) => void; * }} * Platform */ +// This function is duplicated in adapter-vercel /** @param {import('@sveltejs/kit').Builder} builder */ -function vercel_routes(builder) { +function static_vercel_config(builder) { /** @type {any[]} */ - const routes = [ - { - src: `/${builder.config.kit.appDir}/immutable/.+`, - headers: { - 'cache-control': 'public, immutable, max-age=31536000' - } - } - ]; + const prerendered_redirects = []; + + /** @type {Record} */ + const overrides = {}; - // explicit redirects for (const [src, redirect] of builder.prerendered.redirects) { - routes.push({ + prerendered_redirects.push({ src, headers: { Location: redirect.location @@ -32,32 +28,35 @@ function vercel_routes(builder) { }); } - // prerendered pages - for (const [src, page] of builder.prerendered.pages) { - routes.push({ - src, - dest: `${builder.config.kit.appDir}/prerendered/${page.file}` - }); - } + for (const [path, page] of builder.prerendered.pages) { + if (path.endsWith('/') && path !== '/') { + prerendered_redirects.push( + { src: path, dest: path.slice(0, -1) }, + { src: path.slice(0, -1), status: 308, headers: { Location: path } } + ); - // implicit redirects (trailing slashes) - for (const [src] of builder.prerendered.pages) { - if (src !== '/') { - routes.push({ - src: src.endsWith('/') ? src.slice(0, -1) : src + '/', - headers: { - location: src - }, - status: 308 - }); + overrides[page.file] = { path: path.slice(1, -1) }; + } else { + overrides[page.file] = { path: path.slice(1) }; } } - routes.push({ - handle: 'filesystem' - }); - - return routes; + return { + version: 3, + routes: [ + ...prerendered_redirects, + { + src: `/${builder.getAppPath()}/immutable/.+`, + headers: { + 'cache-control': 'public, immutable, max-age=31536000' + } + }, + { + handle: 'filesystem' + } + ], + overrides + }; } /** @type {Platform[]} */ @@ -65,18 +64,12 @@ export const platforms = [ { name: 'Vercel', test: () => !!process.env.VERCEL, - defaults: (config) => ({ - pages: `.vercel/output/static/${config.kit.appDir}/prerendered`, - assets: '.vercel/output/static' - }), + defaults: { + pages: '.vercel/output/static' + }, done: (builder) => { - fs.writeFileSync( - '.vercel/output/config.json', - JSON.stringify({ - version: 3, - routes: vercel_routes(builder) - }) - ); + const config = static_vercel_config(builder); + fs.writeFileSync('.vercel/output/config.json', JSON.stringify(config, null, ' ')); } } ]; diff --git a/packages/adapter-vercel/index.js b/packages/adapter-vercel/index.js index 69ab0a8ba9d5..529225d7cf28 100644 --- a/packages/adapter-vercel/index.js +++ b/packages/adapter-vercel/index.js @@ -25,48 +25,7 @@ const plugin = function ({ external = [], edge, split } = {}) { functions: `${dir}/functions` }; - /** @type {any[]} */ - const prerendered_redirects = []; - - /** @type {Record} */ - const overrides = {}; - - for (const [src, redirect] of builder.prerendered.redirects) { - prerendered_redirects.push({ - src, - headers: { - Location: redirect.location - }, - status: redirect.status - }); - } - - for (const [path, page] of builder.prerendered.pages) { - if (path.endsWith('/') && path !== '/') { - prerendered_redirects.push( - { src: path, dest: path.slice(0, -1) }, - { src: path.slice(0, -1), status: 308, headers: { Location: path } } - ); - - overrides[page.file] = { path: path.slice(1, -1) }; - } else { - overrides[page.file] = { path: path.slice(1) }; - } - } - - /** @type {any[]} */ - const routes = [ - ...prerendered_redirects, - { - src: `/${builder.getAppPath()}/.+`, - headers: { - 'cache-control': 'public, immutable, max-age=31536000' - } - }, - { - handle: 'filesystem' - } - ]; + const config = static_vercel_config(builder); builder.log.minor('Generating serverless function...'); @@ -97,7 +56,7 @@ const plugin = function ({ external = [], edge, split } = {}) { `nodejs${node_version.major}.x` ); - routes.push({ src: pattern, dest: `/${name}` }); + config.routes.push({ src: pattern, dest: `/${name}` }); } /** @@ -142,7 +101,7 @@ const plugin = function ({ external = [], edge, split } = {}) { }) ); - routes.push({ src: pattern, dest: `/${name}` }); + config.routes.push({ src: pattern, dest: `/${name}` }); } const generate_function = edge ? generate_edge_function : generate_serverless_function; @@ -182,18 +141,7 @@ const plugin = function ({ external = [], edge, split } = {}) { builder.log.minor('Writing routes...'); - write( - `${dir}/config.json`, - JSON.stringify( - { - version: 3, - routes, - overrides - }, - null, - ' ' - ) - ); + write(`${dir}/config.json`, JSON.stringify(config, null, ' ')); } }; }; @@ -225,6 +173,56 @@ function get_node_version() { return { major, full }; } +// This function is duplicated in adapter-static +/** @param {import('@sveltejs/kit').Builder} builder */ +function static_vercel_config(builder) { + /** @type {any[]} */ + const prerendered_redirects = []; + + /** @type {Record} */ + const overrides = {}; + + for (const [src, redirect] of builder.prerendered.redirects) { + prerendered_redirects.push({ + src, + headers: { + Location: redirect.location + }, + status: redirect.status + }); + } + + for (const [path, page] of builder.prerendered.pages) { + if (path.endsWith('/') && path !== '/') { + prerendered_redirects.push( + { src: path, dest: path.slice(0, -1) }, + { src: path.slice(0, -1), status: 308, headers: { Location: path } } + ); + + overrides[page.file] = { path: path.slice(1, -1) }; + } else { + overrides[page.file] = { path: path.slice(1) }; + } + } + + return { + version: 3, + routes: [ + ...prerendered_redirects, + { + src: `/${builder.getAppPath()}/immutable/.+`, + headers: { + 'cache-control': 'public, immutable, max-age=31536000' + } + }, + { + handle: 'filesystem' + } + ], + overrides + }; +} + /** * @param {import('@sveltejs/kit').Builder} builder * @param {string} entry