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;
|
cacheDir?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
redirects?: Record<string, string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @name site
|
* @name site
|
||||||
|
@ -1704,7 +1709,7 @@ export interface AstroPluginOptions {
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RouteType = 'page' | 'endpoint';
|
export type RouteType = 'page' | 'endpoint' | 'redirect';
|
||||||
|
|
||||||
export interface RoutePart {
|
export interface RoutePart {
|
||||||
content: string;
|
content: string;
|
||||||
|
|
|
@ -26,6 +26,7 @@ export function getOutFolder(
|
||||||
case 'endpoint':
|
case 'endpoint':
|
||||||
return new URL('.' + appendForwardSlash(npath.dirname(pathname)), outRoot);
|
return new URL('.' + appendForwardSlash(npath.dirname(pathname)), outRoot);
|
||||||
case 'page':
|
case 'page':
|
||||||
|
case 'redirect':
|
||||||
switch (astroConfig.build.format) {
|
switch (astroConfig.build.format) {
|
||||||
case 'directory': {
|
case 'directory': {
|
||||||
if (STATUS_CODE_PAGES.has(pathname)) {
|
if (STATUS_CODE_PAGES.has(pathname)) {
|
||||||
|
@ -51,6 +52,7 @@ export function getOutFile(
|
||||||
case 'endpoint':
|
case 'endpoint':
|
||||||
return new URL(npath.basename(pathname), outFolder);
|
return new URL(npath.basename(pathname), outFolder);
|
||||||
case 'page':
|
case 'page':
|
||||||
|
case 'redirect':
|
||||||
switch (astroConfig.build.format) {
|
switch (astroConfig.build.format) {
|
||||||
case 'directory': {
|
case 'directory': {
|
||||||
if (STATUS_CODE_PAGES.has(pathname)) {
|
if (STATUS_CODE_PAGES.has(pathname)) {
|
||||||
|
|
|
@ -178,14 +178,18 @@ async function generatePage(
|
||||||
.map(({ sheet }) => sheet)
|
.map(({ sheet }) => sheet)
|
||||||
.reduce(mergeInlineCss, []);
|
.reduce(mergeInlineCss, []);
|
||||||
|
|
||||||
const pageModule = ssrEntry.pageMap?.get(pageData.component);
|
let pageModule = ssrEntry.pageMap?.get(pageData.component);
|
||||||
const middleware = ssrEntry.middleware;
|
const middleware = ssrEntry.middleware;
|
||||||
|
|
||||||
if (!pageModule) {
|
if (!pageModule) {
|
||||||
|
if(pageData.route.type === 'redirect') {
|
||||||
|
pageModule = { 'default': Function.prototype as any };
|
||||||
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unable to find the module for ${pageData.component}. This is unexpected and likely a bug in Astro, please report.`
|
`Unable to find the module for ${pageData.component}. This is unexpected and likely a bug in Astro, please report.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldSkipDraft(pageModule, opts.settings)) {
|
if (shouldSkipDraft(pageModule, opts.settings)) {
|
||||||
info(opts.logging, null, `${magenta('⚠️')} Skipping draft ${pageData.route.component}`);
|
info(opts.logging, null, `${magenta('⚠️')} Skipping draft ${pageData.route.component}`);
|
||||||
|
|
|
@ -35,6 +35,9 @@ export function vitePluginPages(opts: StaticBuildOptions, internals: BuildIntern
|
||||||
let imports = [];
|
let imports = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (const pageData of eachPageData(internals)) {
|
for (const pageData of eachPageData(internals)) {
|
||||||
|
if(pageData.route.type === 'redirect') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const variable = `_page${i}`;
|
const variable = `_page${i}`;
|
||||||
imports.push(`import * as ${variable} from ${JSON.stringify(pageData.moduleSpecifier)};`);
|
imports.push(`import * as ${variable} from ${JSON.stringify(pageData.moduleSpecifier)};`);
|
||||||
importMap += `[${JSON.stringify(pageData.component)}, ${variable}],`;
|
importMap += `[${JSON.stringify(pageData.component)}, ${variable}],`;
|
||||||
|
|
|
@ -36,6 +36,7 @@ const ASTRO_CONFIG_DEFAULTS: AstroUserConfig & any = {
|
||||||
},
|
},
|
||||||
vite: {},
|
vite: {},
|
||||||
legacy: {},
|
legacy: {},
|
||||||
|
redirects: {},
|
||||||
experimental: {
|
experimental: {
|
||||||
assets: false,
|
assets: false,
|
||||||
inlineStylesheets: 'never',
|
inlineStylesheets: 'never',
|
||||||
|
@ -133,6 +134,7 @@ export const AstroConfigSchema = z.object({
|
||||||
.optional()
|
.optional()
|
||||||
.default({})
|
.default({})
|
||||||
),
|
),
|
||||||
|
redirects: z.record(z.string(), z.string()).default(ASTRO_CONFIG_DEFAULTS.redirects),
|
||||||
image: z
|
image: z
|
||||||
.object({
|
.object({
|
||||||
service: z.object({
|
service: z.object({
|
||||||
|
|
|
@ -111,6 +111,15 @@ export type RenderPage = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function renderPage({ mod, renderContext, env, apiContext }: 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
|
// Validate the page component before rendering the page
|
||||||
const Component = mod.default;
|
const Component = mod.default;
|
||||||
if (!Component)
|
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 {
|
return {
|
||||||
routes,
|
routes,
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,9 @@ describe('SSG - Redirects', () => {
|
||||||
adapter: netlifyStatic(),
|
adapter: netlifyStatic(),
|
||||||
site: `http://example.com`,
|
site: `http://example.com`,
|
||||||
integrations: [testIntegration()],
|
integrations: [testIntegration()],
|
||||||
|
redirects: {
|
||||||
|
'/other': '/'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
@ -22,6 +25,9 @@ describe('SSG - Redirects', () => {
|
||||||
it('Creates a redirects file', async () => {
|
it('Creates a redirects file', async () => {
|
||||||
let redirects = await fixture.readFile('/_redirects');
|
let redirects = await fixture.readFile('/_redirects');
|
||||||
let parts = redirects.split(/\s+/);
|
let parts = redirects.split(/\s+/);
|
||||||
expect(parts).to.deep.equal(['/nope', '/', '301']);
|
expect(parts).to.deep.equal([
|
||||||
|
'/other', '/', '301',
|
||||||
|
'/nope', '/', '301'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue