Support in Netlify as well
This commit is contained in:
parent
ef3ea942cc
commit
d6b7104722
8 changed files with 76 additions and 6 deletions
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -178,13 +178,17 @@ 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) {
|
||||
throw new Error(
|
||||
`Unable to find the module for ${pageData.component}. This is unexpected and likely a bug in Astro, please report.`
|
||||
);
|
||||
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)) {
|
||||
|
|
|
@ -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}],`;
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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'
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue