Support in Netlify as well

This commit is contained in:
Matthew Phillips 2023-05-11 15:54:10 -04:00
parent ef3ea942cc
commit d6b7104722
8 changed files with 76 additions and 6 deletions

View file

@ -447,6 +447,11 @@ export interface AstroUserConfig {
*/
cacheDir?: string;
/**
* TODO
*/
redirects?: Record<string, string>;
/**
* @docs
* @name site
@ -1704,7 +1709,7 @@ export interface AstroPluginOptions {
logging: LogOptions;
}
export type RouteType = 'page' | 'endpoint';
export type RouteType = 'page' | 'endpoint' | 'redirect';
export interface RoutePart {
content: string;

View file

@ -26,6 +26,7 @@ export function getOutFolder(
case 'endpoint':
return new URL('.' + appendForwardSlash(npath.dirname(pathname)), outRoot);
case 'page':
case 'redirect':
switch (astroConfig.build.format) {
case 'directory': {
if (STATUS_CODE_PAGES.has(pathname)) {
@ -51,6 +52,7 @@ export function getOutFile(
case 'endpoint':
return new URL(npath.basename(pathname), outFolder);
case 'page':
case 'redirect':
switch (astroConfig.build.format) {
case 'directory': {
if (STATUS_CODE_PAGES.has(pathname)) {

View file

@ -178,14 +178,18 @@ async function generatePage(
.map(({ sheet }) => sheet)
.reduce(mergeInlineCss, []);
const pageModule = ssrEntry.pageMap?.get(pageData.component);
let pageModule = ssrEntry.pageMap?.get(pageData.component);
const middleware = ssrEntry.middleware;
if (!pageModule) {
if(pageData.route.type === 'redirect') {
pageModule = { 'default': Function.prototype as any };
} else {
throw new Error(
`Unable to find the module for ${pageData.component}. This is unexpected and likely a bug in Astro, please report.`
);
}
}
if (shouldSkipDraft(pageModule, opts.settings)) {
info(opts.logging, null, `${magenta('⚠️')} Skipping draft ${pageData.route.component}`);

View file

@ -35,6 +35,9 @@ export function vitePluginPages(opts: StaticBuildOptions, internals: BuildIntern
let imports = [];
let i = 0;
for (const pageData of eachPageData(internals)) {
if(pageData.route.type === 'redirect') {
continue;
}
const variable = `_page${i}`;
imports.push(`import * as ${variable} from ${JSON.stringify(pageData.moduleSpecifier)};`);
importMap += `[${JSON.stringify(pageData.component)}, ${variable}],`;

View file

@ -36,6 +36,7 @@ const ASTRO_CONFIG_DEFAULTS: AstroUserConfig & any = {
},
vite: {},
legacy: {},
redirects: {},
experimental: {
assets: false,
inlineStylesheets: 'never',
@ -133,6 +134,7 @@ export const AstroConfigSchema = z.object({
.optional()
.default({})
),
redirects: z.record(z.string(), z.string()).default(ASTRO_CONFIG_DEFAULTS.redirects),
image: z
.object({
service: z.object({

View file

@ -111,6 +111,15 @@ export type RenderPage = {
};
export async function renderPage({ mod, renderContext, env, apiContext }: RenderPage) {
if(renderContext.route?.type === 'redirect') {
return new Response(null, {
status: 301,
headers: {
'location': renderContext.route.redirect!
}
});
}
// Validate the page component before rendering the page
const Component = mod.default;
if (!Component)

View file

@ -412,6 +412,45 @@ export function createRouteManifest(
});
});
Object.entries(settings.config.redirects).forEach(([from, to]) => {
const trailingSlash = config.trailingSlash;
const segments = removeLeadingForwardSlash(from)
.split(path.posix.sep)
.filter(Boolean)
.map((s: string) => {
validateSegment(s);
return getParts(s, from);
});
const pattern = getPattern(segments, settings.config.base, trailingSlash);
const generate = getRouteGenerator(segments, trailingSlash);
const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic)
? `/${segments.map((segment) => segment[0].content).join('/')}`
: null;
const params = segments
.flat()
.filter((p) => p.dynamic)
.map((p) => p.content);
const route = `/${segments
.map(([{ dynamic, content }]) => (dynamic ? `[${content}]` : content))
.join('/')}`.toLowerCase();
routes.unshift({
type: 'redirect',
route,
pattern,
segments,
params,
component: '',
generate,
pathname: pathname || void 0,
prerender: false,
redirect: to
});
});
return {
routes,
};

View file

@ -15,6 +15,9 @@ describe('SSG - Redirects', () => {
adapter: netlifyStatic(),
site: `http://example.com`,
integrations: [testIntegration()],
redirects: {
'/other': '/'
}
});
await fixture.build();
});
@ -22,6 +25,9 @@ describe('SSG - Redirects', () => {
it('Creates a redirects file', async () => {
let redirects = await fixture.readFile('/_redirects');
let parts = redirects.split(/\s+/);
expect(parts).to.deep.equal(['/nope', '/', '301']);
expect(parts).to.deep.equal([
'/other', '/', '301',
'/nope', '/', '301'
]);
});
});