Implement support for redirects config in the Vercel adapter
This commit is contained in:
parent
11a517b1f1
commit
b8ef648f8c
8 changed files with 148 additions and 20 deletions
|
@ -177,7 +177,7 @@ async function generatePage(
|
|||
if(pageData.route.redirectRoute) {
|
||||
pageModulePromise = ssrEntry.pageMap?.get(pageData.route.redirectRoute!.component);
|
||||
} else {
|
||||
pageModulePromise = { default: () => {} } as any;
|
||||
pageModulePromise = () => Promise.resolve<any>({ default: () => {} });
|
||||
}
|
||||
}
|
||||
if (!pageModulePromise) {
|
||||
|
|
|
@ -36,6 +36,10 @@ function getMatchPattern(segments: RoutePart[][]) {
|
|||
.join('');
|
||||
}
|
||||
|
||||
function appendTrailingSlash(route: string): string {
|
||||
return route.at(-1) === '/' ? route : route + '/';
|
||||
}
|
||||
|
||||
function getReplacePattern(segments: RoutePart[][]) {
|
||||
let n = 0;
|
||||
let result = '';
|
||||
|
@ -54,28 +58,44 @@ function getReplacePattern(segments: RoutePart[][]) {
|
|||
return result;
|
||||
}
|
||||
|
||||
function getRedirectLocation(route: RouteData, config: AstroConfig): string {
|
||||
if(route.redirectRoute) {
|
||||
const pattern = getReplacePattern(route.redirectRoute.segments);
|
||||
const path = (config.trailingSlash === 'always' ? appendTrailingSlash(pattern) : pattern);
|
||||
return config.base + path;
|
||||
} else {
|
||||
return config.base + route.redirect;
|
||||
}
|
||||
}
|
||||
|
||||
export function getRedirects(routes: RouteData[], config: AstroConfig): VercelRoute[] {
|
||||
let redirects: VercelRoute[] = [];
|
||||
|
||||
if (config.trailingSlash === 'always') {
|
||||
for (const route of routes) {
|
||||
if (route.type !== 'page' || route.segments.length === 0) continue;
|
||||
|
||||
redirects.push({
|
||||
src: config.base + getMatchPattern(route.segments),
|
||||
headers: { Location: config.base + getReplacePattern(route.segments) + '/' },
|
||||
status: 308,
|
||||
});
|
||||
}
|
||||
} else if (config.trailingSlash === 'never') {
|
||||
for (const route of routes) {
|
||||
if (route.type !== 'page' || route.segments.length === 0) continue;
|
||||
|
||||
redirects.push({
|
||||
src: config.base + getMatchPattern(route.segments) + '/',
|
||||
headers: { Location: config.base + getReplacePattern(route.segments) },
|
||||
status: 308,
|
||||
});
|
||||
for(const route of routes) {
|
||||
if(route.type === 'redirect') {
|
||||
if(true || route.pathname) {
|
||||
redirects.push({
|
||||
src: config.base + getMatchPattern(route.segments),
|
||||
headers: { Location: getRedirectLocation(route, config) },
|
||||
status: 301
|
||||
})
|
||||
} else {
|
||||
console.error(`Dynamic routes not yet supported`);
|
||||
}
|
||||
} else if (route.type === 'page') {
|
||||
if (config.trailingSlash === 'always') {
|
||||
redirects.push({
|
||||
src: config.base + getMatchPattern(route.segments),
|
||||
headers: { Location: config.base + getReplacePattern(route.segments) + '/' },
|
||||
status: 308,
|
||||
});
|
||||
} else if (config.trailingSlash === 'never') {
|
||||
redirects.push({
|
||||
src: config.base + getMatchPattern(route.segments) + '/',
|
||||
headers: { Location: config.base + getReplacePattern(route.segments) },
|
||||
status: 308,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
9
packages/integrations/vercel/test/fixtures/redirects/astro.config.mjs
vendored
Normal file
9
packages/integrations/vercel/test/fixtures/redirects/astro.config.mjs
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
import vercel from '@astrojs/vercel/static';
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
export default defineConfig({
|
||||
adapter: vercel({imageService: true}),
|
||||
experimental: {
|
||||
assets: true
|
||||
}
|
||||
});
|
9
packages/integrations/vercel/test/fixtures/redirects/package.json
vendored
Normal file
9
packages/integrations/vercel/test/fixtures/redirects/package.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "@test/astro-vercel-redirects",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@astrojs/vercel": "workspace:*",
|
||||
"astro": "workspace:*"
|
||||
}
|
||||
}
|
8
packages/integrations/vercel/test/fixtures/redirects/src/pages/index.astro
vendored
Normal file
8
packages/integrations/vercel/test/fixtures/redirects/src/pages/index.astro
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Testing</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Testing</h1>
|
||||
</body>
|
||||
</html>
|
25
packages/integrations/vercel/test/fixtures/redirects/src/pages/team/articles/[...slug].astro
vendored
Normal file
25
packages/integrations/vercel/test/fixtures/redirects/src/pages/team/articles/[...slug].astro
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
export const getStaticPaths = (async () => {
|
||||
const posts = [
|
||||
{ slug: 'one', data: {draft: false, title: 'One'} },
|
||||
{ slug: 'two', data: {draft: false, title: 'Two'} }
|
||||
];
|
||||
return posts.map((post) => {
|
||||
return {
|
||||
params: { slug: post.slug },
|
||||
props: { draft: post.data.draft, title: post.data.title },
|
||||
};
|
||||
});
|
||||
})
|
||||
|
||||
const { slug } = Astro.params;
|
||||
const { title } = Astro.props;
|
||||
---
|
||||
<html>
|
||||
<head>
|
||||
<title>{ title }</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{ title }</h1>
|
||||
</body>
|
||||
</html>
|
48
packages/integrations/vercel/test/redirects.test.js
Normal file
48
packages/integrations/vercel/test/redirects.test.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { expect } from 'chai';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
describe('Redirects', () => {
|
||||
/** @type {import('../../../astro/test/test-utils.js').Fixture} */
|
||||
let fixture;
|
||||
|
||||
before(async () => {
|
||||
fixture = await loadFixture({
|
||||
root: './fixtures/redirects/',
|
||||
redirects: {
|
||||
'/one': '/',
|
||||
'/two': '/',
|
||||
'/blog/[...slug]': '/team/articles/[...slug]',
|
||||
}
|
||||
});
|
||||
await fixture.build();
|
||||
});
|
||||
|
||||
async function getConfig() {
|
||||
const json = await fixture.readFile('../.vercel/output/config.json');
|
||||
const config = JSON.parse(json);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
it('define static routes', async () => {
|
||||
const config = await getConfig();
|
||||
|
||||
const oneRoute = config.routes.find(r => r.src === '/\\/one');
|
||||
expect(oneRoute.headers.Location).to.equal('/');
|
||||
expect(oneRoute.status).to.equal(301);
|
||||
|
||||
const twoRoute = config.routes.find(r => r.src === '/\\/one');
|
||||
expect(twoRoute.headers.Location).to.equal('/');
|
||||
expect(twoRoute.status).to.equal(301);
|
||||
});
|
||||
|
||||
it('defines dynamic routes', async () => {
|
||||
const config = await getConfig();
|
||||
|
||||
const blogRoute = config.routes.find(r => r.src.startsWith('/\\/blog'));
|
||||
expect(blogRoute).to.not.be.undefined;
|
||||
expect(blogRoute.headers.Location.startsWith('/team/articles')).to.equal(true);
|
||||
expect(blogRoute.status).to.equal(301);
|
||||
});
|
||||
});
|
|
@ -4868,6 +4868,15 @@ importers:
|
|||
specifier: workspace:*
|
||||
version: link:../../../../../astro
|
||||
|
||||
packages/integrations/vercel/test/fixtures/redirects:
|
||||
dependencies:
|
||||
'@astrojs/vercel':
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../../../../astro
|
||||
|
||||
packages/integrations/vercel/test/fixtures/serverless-prerender:
|
||||
dependencies:
|
||||
'@astrojs/vercel':
|
||||
|
|
Loading…
Reference in a new issue