Fix double prepended forward slash in certain cases (#7091)
* test: add test with no base * fix: don't always prepend a forward slash * chore: changeset * `'/' + base` ------> `prependForwardSlash(base)`
This commit is contained in:
parent
f994ebdb53
commit
cd410c5eb7
3 changed files with 105 additions and 53 deletions
5
.changeset/swift-moons-drop.md
Normal file
5
.changeset/swift-moons-drop.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix double prepended forward slash in SSR
|
|
@ -14,7 +14,7 @@ import { call as callEndpoint, createAPIContext } from '../endpoint/index.js';
|
||||||
import { consoleLogDestination } from '../logger/console.js';
|
import { consoleLogDestination } from '../logger/console.js';
|
||||||
import { error, type LogOptions } from '../logger/core.js';
|
import { error, type LogOptions } from '../logger/core.js';
|
||||||
import { callMiddleware } from '../middleware/callMiddleware.js';
|
import { callMiddleware } from '../middleware/callMiddleware.js';
|
||||||
import { removeTrailingForwardSlash } from '../path.js';
|
import { prependForwardSlash, removeTrailingForwardSlash } from '../path.js';
|
||||||
import {
|
import {
|
||||||
createEnvironment,
|
createEnvironment,
|
||||||
createRenderContext,
|
createRenderContext,
|
||||||
|
@ -101,7 +101,7 @@ export class App {
|
||||||
if (this.#manifest.assets.has(url.pathname)) {
|
if (this.#manifest.assets.has(url.pathname)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
let pathname = '/' + this.removeBase(url.pathname);
|
let pathname = prependForwardSlash(this.removeBase(url.pathname));
|
||||||
let routeData = matchRoute(pathname, this.#manifestData);
|
let routeData = matchRoute(pathname, this.#manifestData);
|
||||||
|
|
||||||
if (routeData) {
|
if (routeData) {
|
||||||
|
@ -178,7 +178,7 @@ export class App {
|
||||||
status = 200
|
status = 200
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const pathname = '/' + this.removeBase(url.pathname);
|
const pathname = prependForwardSlash(this.removeBase(url.pathname));
|
||||||
const info = this.#routeDataToRouteInfo.get(routeData!)!;
|
const info = this.#routeDataToRouteInfo.get(routeData!)!;
|
||||||
// may be used in the future for handling rel=modulepreload, rel=icon, rel=manifest etc.
|
// may be used in the future for handling rel=modulepreload, rel=icon, rel=manifest etc.
|
||||||
const links = new Set<never>();
|
const links = new Set<never>();
|
||||||
|
|
|
@ -9,61 +9,108 @@ describe('Prerendering', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
let server;
|
let server;
|
||||||
|
|
||||||
before(async () => {
|
|
||||||
process.env.ASTRO_NODE_AUTOSTART = 'disabled';
|
|
||||||
fixture = await loadFixture({
|
|
||||||
base: '/some-base',
|
|
||||||
root: './fixtures/prerender/',
|
|
||||||
output: 'server',
|
|
||||||
adapter: nodejs({ mode: 'standalone' }),
|
|
||||||
});
|
|
||||||
await fixture.build();
|
|
||||||
const { startServer } = await await load();
|
|
||||||
let res = startServer();
|
|
||||||
server = res.server;
|
|
||||||
});
|
|
||||||
|
|
||||||
after(async () => {
|
|
||||||
await server.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
const mod = await import('./fixtures/prerender/dist/server/entry.mjs');
|
const mod = await import('./fixtures/prerender/dist/server/entry.mjs');
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
it('Can render SSR route', async () => {
|
describe('With base', () => {
|
||||||
const res = await fetch(`http://${server.host}:${server.port}/some-base/one`);
|
before(async () => {
|
||||||
const html = await res.text();
|
process.env.ASTRO_NODE_AUTOSTART = 'disabled';
|
||||||
const $ = cheerio.load(html);
|
fixture = await loadFixture({
|
||||||
|
base: '/some-base',
|
||||||
expect(res.status).to.equal(200);
|
root: './fixtures/prerender/',
|
||||||
expect($('h1').text()).to.equal('One');
|
output: 'server',
|
||||||
});
|
adapter: nodejs({ mode: 'standalone' }),
|
||||||
|
});
|
||||||
it('Can render prerendered route', async () => {
|
await fixture.build();
|
||||||
const res = await fetch(`http://${server.host}:${server.port}/some-base/two`);
|
const { startServer } = await await load();
|
||||||
const html = await res.text();
|
let res = startServer();
|
||||||
const $ = cheerio.load(html);
|
server = res.server;
|
||||||
|
});
|
||||||
expect(res.status).to.equal(200);
|
|
||||||
expect($('h1').text()).to.equal('Two');
|
after(async () => {
|
||||||
});
|
await server.stop();
|
||||||
|
});
|
||||||
it('Can render prerendered route with query params', async () => {
|
|
||||||
const res = await fetch(`http://${server.host}:${server.port}/some-base/two/?foo=bar`);
|
it('Can render SSR route', async () => {
|
||||||
const html = await res.text();
|
const res = await fetch(`http://${server.host}:${server.port}/some-base/one`);
|
||||||
const $ = cheerio.load(html);
|
const html = await res.text();
|
||||||
|
const $ = cheerio.load(html);
|
||||||
expect(res.status).to.equal(200);
|
|
||||||
expect($('h1').text()).to.equal('Two');
|
expect(res.status).to.equal(200);
|
||||||
});
|
expect($('h1').text()).to.equal('One');
|
||||||
|
});
|
||||||
it('Omitting the trailing slash results in a redirect that includes the base', async () => {
|
|
||||||
const res = await fetch(`http://${server.host}:${server.port}/some-base/two`, {
|
it('Can render prerendered route', async () => {
|
||||||
redirect: 'manual',
|
const res = await fetch(`http://${server.host}:${server.port}/some-base/two`);
|
||||||
|
const html = await res.text();
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
|
expect(res.status).to.equal(200);
|
||||||
|
expect($('h1').text()).to.equal('Two');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can render prerendered route with query params', async () => {
|
||||||
|
const res = await fetch(`http://${server.host}:${server.port}/some-base/two/?foo=bar`);
|
||||||
|
const html = await res.text();
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
|
expect(res.status).to.equal(200);
|
||||||
|
expect($('h1').text()).to.equal('Two');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Omitting the trailing slash results in a redirect that includes the base', async () => {
|
||||||
|
const res = await fetch(`http://${server.host}:${server.port}/some-base/two`, {
|
||||||
|
redirect: 'manual',
|
||||||
|
});
|
||||||
|
expect(res.status).to.equal(301);
|
||||||
|
expect(res.headers.get('location')).to.equal('/some-base/two/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('Without base', () => {
|
||||||
|
before(async () => {
|
||||||
|
process.env.ASTRO_NODE_AUTOSTART = 'disabled';
|
||||||
|
fixture = await loadFixture({
|
||||||
|
root: './fixtures/prerender/',
|
||||||
|
output: 'server',
|
||||||
|
adapter: nodejs({ mode: 'standalone' }),
|
||||||
|
});
|
||||||
|
await fixture.build();
|
||||||
|
const { startServer } = await await load();
|
||||||
|
let res = startServer();
|
||||||
|
server = res.server;
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await server.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can render SSR route', async () => {
|
||||||
|
const res = await fetch(`http://${server.host}:${server.port}/one`);
|
||||||
|
const html = await res.text();
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
|
expect(res.status).to.equal(200);
|
||||||
|
expect($('h1').text()).to.equal('One');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can render prerendered route', async () => {
|
||||||
|
const res = await fetch(`http://${server.host}:${server.port}/two`);
|
||||||
|
const html = await res.text();
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
|
expect(res.status).to.equal(200);
|
||||||
|
expect($('h1').text()).to.equal('Two');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can render prerendered route with query params', async () => {
|
||||||
|
const res = await fetch(`http://${server.host}:${server.port}/two/?foo=bar`);
|
||||||
|
const html = await res.text();
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
|
expect(res.status).to.equal(200);
|
||||||
|
expect($('h1').text()).to.equal('Two');
|
||||||
});
|
});
|
||||||
expect(res.status).to.equal(301);
|
|
||||||
expect(res.headers.get('location')).to.equal('/some-base/two/');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue