From c5fb8a6aae097aefa5d7bc1b75904426f50f920d Mon Sep 17 00:00:00 2001 From: Felix Wotschofsky Date: Fri, 5 Jul 2024 18:53:31 +0000 Subject: [PATCH 1/2] feat(vercel): allow external redirects --- .changeset/clean-cows-draw.md | 5 ++++ .../integrations/vercel/src/lib/redirects.ts | 24 +++++++++++++++---- .../vercel/test/redirects.test.js | 9 +++++++ 3 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 .changeset/clean-cows-draw.md diff --git a/.changeset/clean-cows-draw.md b/.changeset/clean-cows-draw.md new file mode 100644 index 000000000000..51192d1f727a --- /dev/null +++ b/.changeset/clean-cows-draw.md @@ -0,0 +1,5 @@ +--- +'@astrojs/vercel': minor +--- + +Allow external redirects to be configured through Astro config diff --git a/packages/integrations/vercel/src/lib/redirects.ts b/packages/integrations/vercel/src/lib/redirects.ts index 1e476cb1f288..c9f120d421ef 100644 --- a/packages/integrations/vercel/src/lib/redirects.ts +++ b/packages/integrations/vercel/src/lib/redirects.ts @@ -85,15 +85,29 @@ function getReplacePattern(segments: RoutePart[][]) { } function getRedirectLocation(route: RouteData, config: AstroConfig): string { + let redirectPath: string; + let forceTrailingSlash = false; + if (route.redirectRoute) { - const pattern = getReplacePattern(route.redirectRoute.segments); - const path = config.trailingSlash === 'always' ? appendForwardSlash(pattern) : pattern; - return pathJoin(config.base, path); + redirectPath = getReplacePattern(route.redirectRoute.segments); + if (config.trailingSlash === 'always') forceTrailingSlash = true; } else if (typeof route.redirect === 'object') { - return pathJoin(config.base, route.redirect.destination); + redirectPath = route.redirect.destination; } else { - return pathJoin(config.base, route.redirect || ''); + redirectPath = route.redirect || ''; + } + + // Is external link - do not transform + const hasProtocol = redirectPath.includes('://'); + if (hasProtocol) { + return redirectPath; } + + if (forceTrailingSlash) { + redirectPath = appendForwardSlash(redirectPath); + } + + return pathJoin(config.base, redirectPath); } function getRedirectStatus(route: RouteData): number { diff --git a/packages/integrations/vercel/test/redirects.test.js b/packages/integrations/vercel/test/redirects.test.js index 57de308e233a..f0ddaef716dc 100644 --- a/packages/integrations/vercel/test/redirects.test.js +++ b/packages/integrations/vercel/test/redirects.test.js @@ -18,6 +18,7 @@ describe('Redirects', () => { }, '/blog/[...slug]': '/team/articles/[...slug]', '/Basic/http-2-0.html': '/posts/http2', + '/google': 'https://google.com' }, trailingSlash: 'always', }); @@ -56,6 +57,14 @@ describe('Redirects', () => { assert.equal(staticRoute.status, 301); }); + it('define external redirects', async () => { + const config = await getConfig(); + + const route = config.routes.find((r) => r.src === '/google'); + assert.equal(route.headers.Location, 'https://google.com'); + assert.equal(route.status, 301); + }); + it('defines dynamic routes', async () => { const config = await getConfig(); From 80ad25b60da37a1a9741517e9f9d43711397eff2 Mon Sep 17 00:00:00 2001 From: Felix Wotschofsky Date: Sun, 21 Jul 2024 23:49:33 +0200 Subject: [PATCH 2/2] Use URL.canParse for detecting external redirects Co-authored-by: Luiz Ferraz --- packages/integrations/vercel/src/lib/redirects.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/integrations/vercel/src/lib/redirects.ts b/packages/integrations/vercel/src/lib/redirects.ts index c9f120d421ef..d70d46a11191 100644 --- a/packages/integrations/vercel/src/lib/redirects.ts +++ b/packages/integrations/vercel/src/lib/redirects.ts @@ -97,9 +97,8 @@ function getRedirectLocation(route: RouteData, config: AstroConfig): string { redirectPath = route.redirect || ''; } - // Is external link - do not transform - const hasProtocol = redirectPath.includes('://'); - if (hasProtocol) { + // Is a full URL - do not transform + if (URL.canParse(redirectPath)) { return redirectPath; }