From 385b447aa1d25eb74e40a2eb58c6e522ed67b083 Mon Sep 17 00:00:00 2001 From: Slawek Kolodziej Date: Mon, 10 Feb 2025 20:41:01 +0100 Subject: [PATCH] feat(vercel): allow defining ISR exclusions with regular expressions --- packages/integrations/vercel/src/index.ts | 38 +++++++++++++++---- .../vercel/test/fixtures/isr/astro.config.mjs | 2 +- .../fixtures/isr/src/pages/api/[dynamic].ts | 3 ++ .../test/fixtures/isr/src/pages/api/index.ts | 3 ++ packages/integrations/vercel/test/isr.test.js | 22 +++++------ 5 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 packages/integrations/vercel/test/fixtures/isr/src/pages/api/[dynamic].ts create mode 100644 packages/integrations/vercel/test/fixtures/isr/src/pages/api/index.ts diff --git a/packages/integrations/vercel/src/index.ts b/packages/integrations/vercel/src/index.ts index 4aeb3e568d20..4779b8412014 100644 --- a/packages/integrations/vercel/src/index.ts +++ b/packages/integrations/vercel/src/index.ts @@ -157,7 +157,7 @@ interface VercelISRConfig { * * @default `[]` */ - exclude?: string[]; + exclude?: (string | RegExp)[]; } export default function vercelAdapter({ @@ -407,20 +407,42 @@ export default function vercelAdapter({ const isrConfig = typeof isr === 'object' ? isr : {}; await builder.buildServerlessFolder(entryFile, NODE_PATH, _config.root); if (isrConfig.exclude?.length) { + const expandedExclusions = isrConfig.exclude.reduce((acc, exclusion) => { + if (exclusion instanceof RegExp) { + return [ + ...acc, + ...routes.filter(route => exclusion.test(route.pattern)).map(route => route.pattern) + ] + } + + return [...acc, exclusion]; + }, []); + const dest = _middlewareEntryPoint ? MIDDLEWARE_PATH : NODE_PATH; - for (const route of isrConfig.exclude) { + for (const route of expandedExclusions) { // vercel interprets src as a regex pattern, so we need to escape it routeDefinitions.push({ src: escapeRegex(route), dest }); } } await builder.buildISRFolder(entryFile, '_isr', isrConfig, _config.root); for (const route of routes) { - const src = route.patternRegex.source; - const dest = - src.startsWith('^\\/_image') || src.startsWith('^\\/_server-islands') - ? NODE_PATH - : ISR_PATH; - if (!route.isPrerendered) routeDefinitions.push({ src, dest }); + // Do not create _isr route entries for excluded routes + const excludeRouteFromIsr = isrConfig.exclude?.some(exclusion => { + if (exclusion instanceof RegExp) { + return exclusion.test(route.pattern); + } + + return exclusion === route.pattern; + }); + + if (!excludeRouteFromIsr) { + const src = route.patternRegex.source; + const dest = + src.startsWith('^\\/_image') || src.startsWith('^\\/_server-islands') + ? NODE_PATH + : ISR_PATH; + if (!route.isPrerendered) routeDefinitions.push({ src, dest }); + } } } else { await builder.buildServerlessFolder(entryFile, NODE_PATH, _config.root); diff --git a/packages/integrations/vercel/test/fixtures/isr/astro.config.mjs b/packages/integrations/vercel/test/fixtures/isr/astro.config.mjs index 5e2ce8263502..3bc1a44b51a7 100644 --- a/packages/integrations/vercel/test/fixtures/isr/astro.config.mjs +++ b/packages/integrations/vercel/test/fixtures/isr/astro.config.mjs @@ -7,7 +7,7 @@ export default defineConfig({ isr: { bypassToken: "1c9e601d-9943-4e7c-9575-005556d774a8", expiration: 120, - exclude: ["/two", "/excluded/[dynamic]", "/excluded/[...rest]"] + exclude: ["/two", "/excluded/[dynamic]", "/excluded/[...rest]", /^\/api/] } }) }); diff --git a/packages/integrations/vercel/test/fixtures/isr/src/pages/api/[dynamic].ts b/packages/integrations/vercel/test/fixtures/isr/src/pages/api/[dynamic].ts new file mode 100644 index 000000000000..ecbac57c951d --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/isr/src/pages/api/[dynamic].ts @@ -0,0 +1,3 @@ +export async function GET({ params }) { + return new Response(`OK ${params.dynamic}`) +} diff --git a/packages/integrations/vercel/test/fixtures/isr/src/pages/api/index.ts b/packages/integrations/vercel/test/fixtures/isr/src/pages/api/index.ts new file mode 100644 index 000000000000..fd34254521e2 --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/isr/src/pages/api/index.ts @@ -0,0 +1,3 @@ +export async function GET() { + return new Response("OK") +} diff --git a/packages/integrations/vercel/test/isr.test.js b/packages/integrations/vercel/test/isr.test.js index 1e5b329ef6dd..c2cf9833def2 100644 --- a/packages/integrations/vercel/test/isr.test.js +++ b/packages/integrations/vercel/test/isr.test.js @@ -42,29 +42,25 @@ describe('ISR', () => { dest: '_render', }, { - src: '^/_server-islands/([^/]+?)/?$', - dest: '_render', + src: "^/api/([^/]+?)$", + dest: "_render" }, { - src: '^/_image/?$', - dest: '_render', + src: "^/api$", + dest: "_render" }, { - src: '^/excluded/([^/]+?)/?$', - dest: '/_isr?x_astro_path=$0', + src: '^/_server-islands/([^/]+?)/?$', + dest: '_render', }, { - src: '^/excluded(?:/(.*?))?/?$', - dest: '/_isr?x_astro_path=$0', + src: '^/_image/?$', + dest: '_render', }, { src: '^/one/?$', dest: '/_isr?x_astro_path=$0', - }, - { - src: '^/two/?$', - dest: '/_isr?x_astro_path=$0', - }, + } ]); }); });