From d49a537f2aaccd132154a15f1da4db471272ee90 Mon Sep 17 00:00:00 2001 From: Mark Jaquith Date: Tue, 1 Oct 2024 15:58:14 -0400 Subject: [PATCH 1/2] Use IE conditional comment placeholders for server island start markers (#12090) These placeholders are much less likely to be removed by HTML minifiers, because they have traditionally been used to change the behavior of site. --- .changeset/rich-apes-divide.md | 5 +++++ packages/astro/src/runtime/server/render/server-islands.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/rich-apes-divide.md diff --git a/.changeset/rich-apes-divide.md b/.changeset/rich-apes-divide.md new file mode 100644 index 000000000000..c0f70e5b9696 --- /dev/null +++ b/.changeset/rich-apes-divide.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Server islands: changes the server island HTML placeholder comment so that it is much less likely to get removed by HTML minifiers. diff --git a/packages/astro/src/runtime/server/render/server-islands.ts b/packages/astro/src/runtime/server/render/server-islands.ts index 0a072113447b..6dd06b8d7b1a 100644 --- a/packages/astro/src/runtime/server/render/server-islands.ts +++ b/packages/astro/src/runtime/server/render/server-islands.ts @@ -47,7 +47,7 @@ export function renderServerIsland( } } - destination.write(''); + destination.write(''); // Render the slots const renderedSlots: Record = {}; @@ -88,7 +88,7 @@ if(response.status === 200 && response.headers.get('content-type') === 'text/htm // Swap! while(script.previousSibling && script.previousSibling.nodeType !== 8 && - script.previousSibling.data !== 'server-island-start') { + script.previousSibling.data !== '[if astro]>server-island-start Date: Wed, 2 Oct 2024 17:08:36 +0100 Subject: [PATCH 2/2] fix: pass custom statusText in Response (#12105) * fix: pass custom statusText in Response * Add changeset --- .changeset/moody-doors-wink.md | 5 +++++ packages/astro/src/core/app/node.ts | 3 ++- .../astro/src/vite-plugin-astro-server/response.ts | 4 ++-- .../fixtures/ssr-api-route/src/pages/food.json.js | 11 ++++++++--- packages/astro/test/ssr-api-route.test.js | 12 ++++++++++++ 5 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 .changeset/moody-doors-wink.md diff --git a/.changeset/moody-doors-wink.md b/.changeset/moody-doors-wink.md new file mode 100644 index 000000000000..38a7cadf9bd9 --- /dev/null +++ b/.changeset/moody-doors-wink.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Returns custom statusText that has been set in a Response diff --git a/packages/astro/src/core/app/node.ts b/packages/astro/src/core/app/node.ts index f9afa6189d5a..9fa1b645ff22 100644 --- a/packages/astro/src/core/app/node.ts +++ b/packages/astro/src/core/app/node.ts @@ -107,7 +107,8 @@ export class NodeApp extends App { * @param destination NodeJS ServerResponse */ static async writeResponse(source: Response, destination: ServerResponse) { - const { status, headers, body } = source; + const { status, headers, body, statusText } = source; + destination.statusMessage = statusText; destination.writeHead(status, createOutgoingHttpHeaders(headers)); if (!body) return destination.end(); try { diff --git a/packages/astro/src/vite-plugin-astro-server/response.ts b/packages/astro/src/vite-plugin-astro-server/response.ts index 707a26e4091c..bc316d7c21f2 100644 --- a/packages/astro/src/vite-plugin-astro-server/response.ts +++ b/packages/astro/src/vite-plugin-astro-server/response.ts @@ -53,7 +53,7 @@ export function writeHtmlResponse(res: http.ServerResponse, statusCode: number, } export async function writeWebResponse(res: http.ServerResponse, webResponse: Response) { - const { status, headers, body } = webResponse; + const { status, headers, body, statusText } = webResponse; // Attach any set-cookie headers added via Astro.cookies.set() const setCookieHeaders = Array.from(getSetCookiesFromResponse(webResponse)); @@ -67,7 +67,7 @@ export async function writeWebResponse(res: http.ServerResponse, webResponse: Re if (headers.has('set-cookie')) { _headers['set-cookie'] = headers.getSetCookie(); } - + res.statusMessage = statusText; res.writeHead(status, _headers); if (body) { if (Symbol.for('astro.responseBody') in webResponse) { diff --git a/packages/astro/test/fixtures/ssr-api-route/src/pages/food.json.js b/packages/astro/test/fixtures/ssr-api-route/src/pages/food.json.js index 2d6fb6d1b236..e145757b1342 100644 --- a/packages/astro/test/fixtures/ssr-api-route/src/pages/food.json.js +++ b/packages/astro/test/fixtures/ssr-api-route/src/pages/food.json.js @@ -5,14 +5,19 @@ export function GET() { { name: 'lettuce' }, { name: 'broccoli' }, { name: 'pizza' } - ]) + ]), { + status: 200, + statusText: `tasty`, + } ) } export async function POST({ params, request }) { const body = await request.text(); - return new Response(body === `some data` ? `ok` : `not ok`, { - status: 200, + const ok = body === `some data` + return new Response( ok ? `ok` : `not ok`, { + status: ok ? 200 : 400, + statusText: ok ? `ok` : `not ok`, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } diff --git a/packages/astro/test/ssr-api-route.test.js b/packages/astro/test/ssr-api-route.test.js index 2e7405326fcc..ecdf458472e7 100644 --- a/packages/astro/test/ssr-api-route.test.js +++ b/packages/astro/test/ssr-api-route.test.js @@ -33,6 +33,7 @@ describe('API routes in SSR', () => { const request = new Request('http://example.com/food.json'); const response = await app.render(request); assert.equal(response.status, 200); + assert.equal(response.statusText, 'tasty'); const body = await response.json(); assert.equal(body.length, 3); }); @@ -78,6 +79,17 @@ describe('API routes in SSR', () => { assert.equal(text, 'ok'); }); + it('Can read custom status text from API routes', async () => { + const response = await fixture.fetch('/food.json', { + method: 'POST', + body: `not some data`, + }); + assert.equal(response.status, 400); + assert.equal(response.statusText, 'not ok'); + const text = await response.text(); + assert.equal(text, 'not ok'); + }); + it('Can be passed binary data from multipart formdata', async () => { const formData = new FormData(); const raw = await fs.promises.readFile(