Fix redirects in dev mode (#7342)

* Fix redirects in dev mode

* Adding a changeset
This commit is contained in:
Matthew Phillips 2023-06-09 07:54:14 +03:00 committed by GitHub
parent 3d9a392a09
commit bbcf69e7b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 109 additions and 54 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fix for experimental redirects in dev mode

View file

@ -161,7 +161,7 @@ function isRedirect(statusCode: number) {
}
export function throwIfRedirectNotAllowed(response: Response, config: AstroConfig) {
if (!isServerLikeOutput(config) && isRedirect(response.status)) {
if (!isServerLikeOutput(config) && isRedirect(response.status) && !config.experimental.redirects) {
throw new AstroError(AstroErrorData.StaticRedirectNotAvailable);
}
}

View file

@ -1,6 +1,7 @@
import type { AstroSettings, RouteData } from '../@types/astro';
import { preload, type DevelopmentEnvironment } from '../core/render/dev/index.js';
import { preload, type DevelopmentEnvironment, type ComponentPreload } from '../core/render/dev/index.js';
import { getPrerenderStatus } from './metadata.js';
import { routeIsRedirect, RedirectComponentInstance } from '../core/redirects/index.js';
type GetSortedPreloadedMatchesParams = {
env: DevelopmentEnvironment;
@ -26,14 +27,31 @@ type PreloadAndSetPrerenderStatusParams = {
matches: RouteData[];
settings: AstroSettings;
};
type PreloadAndSetPrerenderStatusResult = {
filePath: URL;
route: RouteData;
preloadedComponent: ComponentPreload;
};
async function preloadAndSetPrerenderStatus({
env,
matches,
settings,
}: PreloadAndSetPrerenderStatusParams) {
}: PreloadAndSetPrerenderStatusParams): Promise<PreloadAndSetPrerenderStatusResult[]> {
const preloaded = await Promise.all(
matches.map(async (route) => {
const filePath = new URL(`./${route.component}`, settings.config.root);
if(routeIsRedirect(route)) {
const preloadedComponent: ComponentPreload = [[], RedirectComponentInstance];
return {
preloadedComponent,
route,
filePath
};
}
const preloadedComponent = await preload({ env, filePath });
// gets the prerender metadata set by the `astro:scanner` vite plugin
@ -46,7 +64,7 @@ async function preloadAndSetPrerenderStatus({
route.prerender = prerenderStatus;
}
return { preloadedComponent, route, filePath } as const;
return { preloadedComponent, route, filePath };
})
);
return preloaded;

View file

@ -65,61 +65,93 @@ describe('Astro.redirect', () => {
});
describe('output: "static"', () => {
before(async () => {
process.env.STATIC_MODE = true;
fixture = await loadFixture({
root: './fixtures/ssr-redirect/',
output: 'static',
experimental: {
redirects: true,
},
redirects: {
'/one': '/',
'/two': '/',
'/blog/[...slug]': '/articles/[...slug]',
'/three': {
status: 302,
destination: '/',
describe('build', () => {
before(async () => {
process.env.STATIC_MODE = true;
fixture = await loadFixture({
root: './fixtures/ssr-redirect/',
output: 'static',
experimental: {
redirects: true,
},
},
redirects: {
'/one': '/',
'/two': '/',
'/blog/[...slug]': '/articles/[...slug]',
'/three': {
status: 302,
destination: '/',
},
},
});
await fixture.build();
});
it('Includes the meta refresh tag in Astro.redirect pages', async () => {
const html = await fixture.readFile('/secret/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/login');
});
it('Includes the meta refresh tag in `redirect` config pages', async () => {
let html = await fixture.readFile('/one/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/');
html = await fixture.readFile('/two/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/');
html = await fixture.readFile('/three/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/');
});
it('Generates page for dynamic routes', async () => {
let html = await fixture.readFile('/blog/one/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/articles/one');
html = await fixture.readFile('/blog/two/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/articles/two');
});
it('Generates redirect pages for redirects created by middleware', async () => {
let html = await fixture.readFile('/middleware-redirect/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/');
});
await fixture.build();
});
it('Includes the meta refresh tag in Astro.redirect pages', async () => {
const html = await fixture.readFile('/secret/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/login');
});
describe('dev', () => {
/** @type {import('./test-utils.js').DevServer} */
let devServer;
before(async () => {
process.env.STATIC_MODE = true;
fixture = await loadFixture({
root: './fixtures/ssr-redirect/',
output: 'static',
experimental: {
redirects: true,
},
redirects: {
'/one': '/',
},
});
devServer = await fixture.startDevServer();
});
it('Includes the meta refresh tag in `redirect` config pages', async () => {
let html = await fixture.readFile('/one/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/');
html = await fixture.readFile('/two/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/');
html = await fixture.readFile('/three/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/');
});
it('Generates page for dynamic routes', async () => {
let html = await fixture.readFile('/blog/one/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/articles/one');
html = await fixture.readFile('/blog/two/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/articles/two');
});
it('Generates redirect pages for redirects created by middleware', async () => {
let html = await fixture.readFile('/middleware-redirect/index.html');
expect(html).to.include('http-equiv="refresh');
expect(html).to.include('url=/');
after(async () => {
await devServer.stop();
});
it('Returns 301', async () => {
let res = await fixture.fetch('/one', {
redirect: 'manual'
});
expect(res.status).to.equal(301);
});
});
});