mirror of
https://github.com/withastro/astro.git
synced 2025-02-17 22:44:24 -05:00
fix(dev): remove params for prerendered pages (#10199)
* fix(dev): remove params for prerendered pages * add test * add changset * deduplicate param removal * format * adjust tests
This commit is contained in:
parent
3de7b2c7ec
commit
6aa660ae7a
9 changed files with 78 additions and 13 deletions
5
.changeset/nice-hats-live.md
Normal file
5
.changeset/nice-hats-live.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"astro": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fixes an issue where prerendered pages had access to query params in dev mode.
|
|
@ -1,5 +1,7 @@
|
||||||
import type { APIContext } from 'astro';
|
import type { APIContext } from 'astro';
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
|
|
||||||
export const POST = async ({ request, redirect }: APIContext) => {
|
export const POST = async ({ request, redirect }: APIContext) => {
|
||||||
const formData = await request.formData();
|
const formData = await request.formData();
|
||||||
const name = formData.get('name');
|
const name = formData.get('name');
|
||||||
|
|
|
@ -3,6 +3,7 @@ import Layout from '../components/Layout.astro';
|
||||||
const method = Astro.url.searchParams.get('method') ?? 'POST';
|
const method = Astro.url.searchParams.get('method') ?? 'POST';
|
||||||
const enctype = Astro.url.searchParams.get('enctype');
|
const enctype = Astro.url.searchParams.get('enctype');
|
||||||
const postShowThrow = Astro.url.searchParams.has('throw') ?? false;
|
const postShowThrow = Astro.url.searchParams.has('throw') ?? false;
|
||||||
|
export const prerender = false;
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
---
|
---
|
||||||
import Layout from '../components/Layout.astro';
|
import Layout from '../components/Layout.astro';
|
||||||
const name = Astro.url.searchParams.get('name');
|
const name = Astro.url.searchParams.get('name');
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
---
|
---
|
||||||
<Layout>
|
<Layout>
|
||||||
<div>Submitted contact: <span id="contact-name">{name}</span></div>
|
<div>Submitted contact: <span id="contact-name">{name}</span></div>
|
||||||
|
|
|
@ -6,6 +6,8 @@ if(Astro.request.method === 'POST') {
|
||||||
const name = formData.get('name');
|
const name = formData.get('name');
|
||||||
return Astro.redirect(`/form-response?name=${name}`);
|
return Astro.redirect(`/form-response?name=${name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
---
|
---
|
||||||
<Layout>
|
<Layout>
|
||||||
<h2>Contact Form</h2>
|
<h2>Contact Form</h2>
|
||||||
|
|
|
@ -13,6 +13,7 @@ export interface CreateRequestOptions {
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
ssr: boolean;
|
ssr: boolean;
|
||||||
locals?: object | undefined;
|
locals?: object | undefined;
|
||||||
|
removeParams?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const clientAddressSymbol = Symbol.for('astro.clientAddress');
|
const clientAddressSymbol = Symbol.for('astro.clientAddress');
|
||||||
|
@ -27,13 +28,21 @@ export function createRequest({
|
||||||
logger,
|
logger,
|
||||||
ssr,
|
ssr,
|
||||||
locals,
|
locals,
|
||||||
|
removeParams = false,
|
||||||
}: CreateRequestOptions): Request {
|
}: CreateRequestOptions): Request {
|
||||||
let headersObj =
|
let headersObj =
|
||||||
headers instanceof Headers
|
headers instanceof Headers
|
||||||
? headers
|
? headers
|
||||||
: new Headers(Object.entries(headers as Record<string, any>));
|
: new Headers(Object.entries(headers as Record<string, any>));
|
||||||
|
|
||||||
const request = new Request(url.toString(), {
|
if (typeof url === 'string') url = new URL(url);
|
||||||
|
|
||||||
|
// HACK! astro:assets uses query params for the injected route in `dev`
|
||||||
|
if (removeParams && url.pathname !== '/_image') {
|
||||||
|
url.search = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = new Request(url, {
|
||||||
method: method,
|
method: method,
|
||||||
headers: headersObj,
|
headers: headersObj,
|
||||||
body,
|
body,
|
||||||
|
|
|
@ -40,17 +40,6 @@ export async function handleRequest({
|
||||||
// Add config.base back to url before passing it to SSR
|
// Add config.base back to url before passing it to SSR
|
||||||
url.pathname = removeTrailingForwardSlash(config.base) + url.pathname;
|
url.pathname = removeTrailingForwardSlash(config.base) + url.pathname;
|
||||||
|
|
||||||
// HACK! astro:assets uses query params for the injected route in `dev`
|
|
||||||
if (!buildingToSSR && pathname !== '/_image') {
|
|
||||||
// Prevent user from depending on search params when not doing SSR.
|
|
||||||
// NOTE: Create an array copy here because deleting-while-iterating
|
|
||||||
// creates bugs where not all search params are removed.
|
|
||||||
const allSearchParams = Array.from(url.searchParams);
|
|
||||||
for (const [key] of allSearchParams) {
|
|
||||||
url.searchParams.delete(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let body: ArrayBuffer | undefined = undefined;
|
let body: ArrayBuffer | undefined = undefined;
|
||||||
if (!(incomingRequest.method === 'GET' || incomingRequest.method === 'HEAD')) {
|
if (!(incomingRequest.method === 'GET' || incomingRequest.method === 'HEAD')) {
|
||||||
let bytes: Uint8Array[] = [];
|
let bytes: Uint8Array[] = [];
|
||||||
|
|
|
@ -229,6 +229,7 @@ export async function handleRoute({
|
||||||
logger,
|
logger,
|
||||||
ssr: buildingToSSR,
|
ssr: buildingToSSR,
|
||||||
clientAddress: buildingToSSR ? incomingRequest.socket.remoteAddress : undefined,
|
clientAddress: buildingToSSR ? incomingRequest.socket.remoteAddress : undefined,
|
||||||
|
removeParams: buildingToSSR === false || route.prerender
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set user specified headers to response object.
|
// Set user specified headers to response object.
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import * as assert from 'node:assert/strict';
|
import * as assert from 'node:assert/strict';
|
||||||
import { describe, it } from 'node:test';
|
import { after, before, describe, it } from 'node:test';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { createContainer } from '../../../dist/core/dev/container.js';
|
||||||
import { createLoader } from '../../../dist/core/module-loader/index.js';
|
import { createLoader } from '../../../dist/core/module-loader/index.js';
|
||||||
import { createRouteManifest } from '../../../dist/core/routing/index.js';
|
import { createRouteManifest } from '../../../dist/core/routing/index.js';
|
||||||
import { createComponent, render } from '../../../dist/runtime/server/index.js';
|
import { createComponent, render } from '../../../dist/runtime/server/index.js';
|
||||||
import { createController, handleRequest } from '../../../dist/vite-plugin-astro-server/index.js';
|
import { createController, handleRequest } from '../../../dist/vite-plugin-astro-server/index.js';
|
||||||
import { DevPipeline } from '../../../dist/vite-plugin-astro-server/pipeline.js';
|
import { DevPipeline } from '../../../dist/vite-plugin-astro-server/pipeline.js';
|
||||||
import { createDevelopmentManifest } from '../../../dist/vite-plugin-astro-server/plugin.js';
|
import { createDevelopmentManifest } from '../../../dist/vite-plugin-astro-server/plugin.js';
|
||||||
|
import testAdapter from '../../test-adapter.js';
|
||||||
import {
|
import {
|
||||||
createAstroModule,
|
createAstroModule,
|
||||||
createBasicSettings,
|
createBasicSettings,
|
||||||
|
@ -73,4 +76,55 @@ describe('vite-plugin-astro-server', () => {
|
||||||
assert.equal(html.includes('<div id="test">'), true);
|
assert.equal(html.includes('<div id="test">'), true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('url', () => {
|
||||||
|
let container;
|
||||||
|
let settings;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
const root = new URL('../../fixtures/api-routes/', import.meta.url);
|
||||||
|
const fileSystem = {
|
||||||
|
'/src/pages/url.astro': `{Astro.request.url}`,
|
||||||
|
'/src/pages/prerendered.astro': `---
|
||||||
|
export const prerender = true;
|
||||||
|
---
|
||||||
|
{Astro.request.url}`,
|
||||||
|
};
|
||||||
|
const fs = createFs(fileSystem, root);
|
||||||
|
settings = await createBasicSettings({
|
||||||
|
root: fileURLToPath(root),
|
||||||
|
output: 'server',
|
||||||
|
adapter: testAdapter(),
|
||||||
|
});
|
||||||
|
container = await createContainer({
|
||||||
|
fs,
|
||||||
|
settings,
|
||||||
|
logger: defaultLogger,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await container.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('params are included', async () => {
|
||||||
|
const { req, res, text } = createRequestAndResponse({
|
||||||
|
method: 'GET',
|
||||||
|
url: '/url?xyz=123',
|
||||||
|
});
|
||||||
|
container.handle(req, res);
|
||||||
|
const html = await text();
|
||||||
|
assert.deepEqual(html, '<!DOCTYPE html>http://undefined/url?xyz=123');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('params are excluded on prerendered routes', async () => {
|
||||||
|
const { req, res, text } = createRequestAndResponse({
|
||||||
|
method: 'GET',
|
||||||
|
url: '/prerendered?xyz=123',
|
||||||
|
});
|
||||||
|
container.handle(req, res);
|
||||||
|
const html = await text();
|
||||||
|
assert.deepEqual(html, '<!DOCTYPE html>http://undefined/prerendered');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue