Skip to content

Commit

Permalink
Fix redirects in dev mode (#7342)
Browse files Browse the repository at this point in the history
* Fix redirects in dev mode

* Adding a changeset
  • Loading branch information
matthewp committed Jun 9, 2023
1 parent 3d9a392 commit bbcf69e
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 54 deletions.
5 changes: 5 additions & 0 deletions .changeset/swift-flies-press.md
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fix for experimental redirects in dev mode
2 changes: 1 addition & 1 deletion packages/astro/src/core/endpoint/index.ts
Expand Up @@ -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);
}
}
24 changes: 21 additions & 3 deletions packages/astro/src/prerender/routing.ts
@@ -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;
Expand All @@ -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
Expand All @@ -46,7 +64,7 @@ async function preloadAndSetPrerenderStatus({
route.prerender = prerenderStatus;
}

return { preloadedComponent, route, filePath } as const;
return { preloadedComponent, route, filePath };
})
);
return preloaded;
Expand Down
132 changes: 82 additions & 50 deletions packages/astro/test/redirects.test.js
Expand Up @@ -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');
});

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');
});
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('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);
});
});
});

Expand Down

0 comments on commit bbcf69e

Please sign in to comment.