Allow redirects in static mode

This commit is contained in:
Matthew Phillips 2023-05-11 15:19:38 -04:00
parent 46e726960f
commit ef3ea942cc
9 changed files with 129 additions and 9 deletions

View file

@ -1724,6 +1724,7 @@ export interface RouteData {
segments: RoutePart[][];
type: RouteType;
prerender: boolean;
redirect?: string;
}
export type SerializedRouteData = Omit<RouteData, 'generate' | 'pattern'> & {

View file

@ -522,9 +522,10 @@ async function generatePath(
case 302: {
const location = response.headers.get("location");
if(!location) {
redirectWithNoLocation();
return void redirectWithNoLocation();
}
body = `<!doctype html><meta http-equiv="refresh" content="0;url=${location}" />`
body = `<!doctype html><meta http-equiv="refresh" content="0;url=${location}" />`;
pageData.route.redirect = location;
break;
}
default: {

View file

@ -1,2 +1,3 @@
export { netlifyEdgeFunctions } from './integration-edge-functions.js';
export { netlifyFunctions as default, netlifyFunctions } from './integration-functions.js';
export { netlifyStatic } from './integration-static.js';

View file

@ -0,0 +1,28 @@
import type { AstroAdapter, AstroConfig, AstroIntegration, RouteData } from 'astro';
import type { Args } from './netlify-functions.js';
import { createRedirects } from './shared.js';
export function netlifyStatic(): AstroIntegration {
let _config: any;
return {
name: '@astrojs/netlify',
hooks: {
'astro:config:done': ({ config }) => {
_config = config;
},
// 'astro:config:setup': ({ config, updateConfig }) => {
// const outDir = dist ?? new URL('./dist/', config.root);
// updateConfig({
// outDir,
// build: {
// client: outDir,
// server: new URL('./.netlify/functions-internal/', config.root),
// },
// });
// },
'astro:build:done': async ({ dir, routes }) => {
await createRedirects(_config, routes, dir, '', 'static');
}
}
};
}

View file

@ -1,12 +1,12 @@
import type { AstroConfig, RouteData } from 'astro';
import fs from 'fs';
type RedirectDefinition = {
export type RedirectDefinition = {
dynamic: boolean;
input: string;
target: string;
weight: 0 | 1;
status: 200 | 404;
status: 200 | 404 | 301;
};
export async function createRedirects(
@ -14,7 +14,7 @@ export async function createRedirects(
routes: RouteData[],
dir: URL,
entryFile: string,
type: 'functions' | 'edge-functions' | 'builders'
type: 'functions' | 'edge-functions' | 'builders' | 'static'
) {
const _redirectsURL = new URL('./_redirects', dir);
const kind = type ?? 'functions';
@ -23,7 +23,19 @@ export async function createRedirects(
for (const route of routes) {
if (route.pathname) {
if (route.distURL) {
if( kind === 'static') {
if(route.redirect) {
definitions.push({
dynamic: false,
input: route.pathname,
target: route.redirect,
status: 301,
weight: 1
});
}
continue;
}
else if (route.distURL) {
definitions.push({
dynamic: false,
input: route.pathname,
@ -68,7 +80,19 @@ export async function createRedirects(
})
.join('/');
if (route.distURL) {
if(kind === 'static') {
if(route.redirect) {
definitions.push({
dynamic: true,
input: pattern,
target: route.redirect,
status: 301,
weight: 1
});
}
continue;
}
else if (route.distURL) {
const target =
`${pattern}` + (config.build.format === 'directory' ? '/index.html' : '.html');
definitions.push({
@ -99,8 +123,8 @@ export async function createRedirects(
}
function prettify(definitions: RedirectDefinition[]) {
let minInputLength = 0,
minTargetLength = 0;
let minInputLength = 4,
minTargetLength = 4;
definitions.sort((a, b) => {
// Find the longest input, so we can format things nicely
if (a.input.length > minInputLength) {

View file

@ -0,0 +1,6 @@
<html>
<head><title>Testing</title></head>
<body>
<h1>Testing</h1>
</body>
</html>

View file

@ -0,0 +1,3 @@
---
return Astro.redirect('/');
---

View file

@ -0,0 +1,27 @@
import { expect } from 'chai';
import { load as cheerioLoad } from 'cheerio';
import { loadFixture, testIntegration } from './test-utils.js';
import { netlifyStatic } from '../../dist/index.js';
import { fileURLToPath } from 'url';
describe('SSG - Redirects', () => {
/** @type {import('../../../astro/test/test-utils').Fixture} */
let fixture;
before(async () => {
fixture = await loadFixture({
root: new URL('./fixtures/redirects/', import.meta.url).toString(),
output: 'static',
adapter: netlifyStatic(),
site: `http://example.com`,
integrations: [testIntegration()],
});
await fixture.build();
});
it('Creates a redirects file', async () => {
let redirects = await fixture.readFile('/_redirects');
let parts = redirects.split(/\s+/);
expect(parts).to.deep.equal(['/nope', '/', '301']);
});
});

View file

@ -0,0 +1,29 @@
// @ts-check
import { fileURLToPath } from 'url';
export * from '../../../../astro/test/test-utils.js';
/**
*
* @returns {import('../../../../astro/dist/types/@types/astro').AstroIntegration}
*/
export function testIntegration() {
return {
name: '@astrojs/netlify/test-integration',
hooks: {
'astro:config:setup': ({ updateConfig }) => {
updateConfig({
vite: {
resolve: {
alias: {
'@astrojs/netlify/netlify-functions.js': fileURLToPath(
new URL('../../dist/netlify-functions.js', import.meta.url)
),
},
},
},
});
},
},
};
}