From bb3b8de29ef5a67457359ccfb2749c1b8a7a5daf Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Sat, 17 Aug 2024 18:52:01 -0400 Subject: [PATCH 1/3] feat: merge exisiting headers with ones loader/action sets Signed-off-by: Logan McAnsh --- packages/remix-fastify/src/plugin.ts | 2 +- packages/remix-fastify/src/server.ts | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/remix-fastify/src/plugin.ts b/packages/remix-fastify/src/plugin.ts index 7d8ab8fd..34bc8197 100644 --- a/packages/remix-fastify/src/plugin.ts +++ b/packages/remix-fastify/src/plugin.ts @@ -155,7 +155,7 @@ export let remixFastify = fp( done(null, payload); }); - let basepath = basename.replace(/\/+$/, "") + "/*"; + let basepath = basename.replace(/\/+$/, "/*"); childServer.all(basepath, remixHandler); }); diff --git a/packages/remix-fastify/src/server.ts b/packages/remix-fastify/src/server.ts index 8e9c8617..e13361a3 100644 --- a/packages/remix-fastify/src/server.ts +++ b/packages/remix-fastify/src/server.ts @@ -124,8 +124,17 @@ export async function sendRemixResponse( ): Promise { reply.status(nodeResponse.status); - for (let [key, values] of nodeResponse.headers.entries()) { - reply.headers({ [key]: values }); + for (let [key, value] of nodeResponse.headers.entries()) { + let currentHeaders = reply.getHeader(key); + if (currentHeaders) { + if (Array.isArray(currentHeaders)) { + reply.headers({ [key]: [...currentHeaders, value] }); + continue; + } + reply.headers({ [key]: [String(currentHeaders), value] }); + continue; + } + reply.headers({ [key]: value }); } if (nodeResponse.body) { From 1d46df2077835c6ad2ae2e523270557a2d7cc7e5 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Sun, 18 Aug 2024 11:40:41 -0400 Subject: [PATCH 2/3] Create eight-planes-suffer.md Signed-off-by: Logan McAnsh --- .changeset/eight-planes-suffer.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/eight-planes-suffer.md diff --git a/.changeset/eight-planes-suffer.md b/.changeset/eight-planes-suffer.md new file mode 100644 index 00000000..928c6744 --- /dev/null +++ b/.changeset/eight-planes-suffer.md @@ -0,0 +1,5 @@ +--- +"@mcansh/remix-fastify": minor +--- + +merge exisiting fastify reply headers with ones loader/action sets From b852fac22267551b12a83ee9c9e3235d8c7e16d3 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Sun, 18 Aug 2024 13:04:16 -0400 Subject: [PATCH 3/3] feat: updated merging of headers Signed-off-by: Logan McAnsh --- .../remix-fastify/__tests__/index.test.ts | 35 +++++++++++++++---- packages/remix-fastify/src/server.ts | 33 +++++++++++++---- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/packages/remix-fastify/__tests__/index.test.ts b/packages/remix-fastify/__tests__/index.test.ts index baf52b62..0379d7ab 100644 --- a/packages/remix-fastify/__tests__/index.test.ts +++ b/packages/remix-fastify/__tests__/index.test.ts @@ -10,6 +10,7 @@ import "@remix-run/node/install"; import type { MockedFunction } from "vitest"; import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; +import type { GetLoadContextFunction, HttpServer } from "../src/server"; import { createRemixHeaders, createRemixRequest, @@ -31,18 +32,20 @@ let mockedCreateRequestHandler = createRemixRequestHandler as MockedFunction< typeof createRemixRequestHandler >; -function createApp() { +function createApp(getLoadContext?: GetLoadContextFunction) { let app = fastify(); - app.all( - "*", - createRequestHandler({ + app.all("*", (request, reply) => { + let handler = createRequestHandler({ // We don't have a real app to test, but it doesn't matter. We // won't ever call through to the real createRequestHandler // @ts-expect-error build: undefined, - }), - ); + getLoadContext, + }); + + return handler(request, reply); + }); return app; } @@ -134,6 +137,26 @@ describe("fastify createRequestHandler", () => { expect(response.statusCode).toBe(204); }); + it("merges headers set by the server and by remix", async () => { + mockedCreateRequestHandler.mockImplementation(() => async () => { + return new Response(null, { + headers: { Link: "; rel=preload; as=style" }, + }); + }); + + let app = createApp((_request, reply) => { + reply.header("Link", "; rel=preload; as=script"); + return {}; + }); + + let response = await app.inject("/"); + + expect(response.headers["link"]).toEqual([ + "; rel=preload; as=style", + "; rel=preload; as=script", + ]); + }); + it("sets headers", async () => { mockedCreateRequestHandler.mockImplementation(() => async () => { let headers = new Headers({ "X-Time-Of-Year": "most wonderful" }); diff --git a/packages/remix-fastify/src/server.ts b/packages/remix-fastify/src/server.ts index e13361a3..b212f9e5 100644 --- a/packages/remix-fastify/src/server.ts +++ b/packages/remix-fastify/src/server.ts @@ -124,17 +124,36 @@ export async function sendRemixResponse( ): Promise { reply.status(nodeResponse.status); + let appliedHeaders = new Map>(); + for (let [key, value] of nodeResponse.headers.entries()) { - let currentHeaders = reply.getHeader(key); - if (currentHeaders) { - if (Array.isArray(currentHeaders)) { - reply.headers({ [key]: [...currentHeaders, value] }); - continue; + let currentFastifyHeader = reply.getHeader(key); + let currentValues = appliedHeaders.get(key) || new Set(); + + if (currentFastifyHeader) { + if (Array.isArray(currentFastifyHeader)) { + for (let header of currentFastifyHeader) { + currentValues.add(value); + currentValues.add(header); + } + } else { + currentValues.add(value); + currentValues.add(currentFastifyHeader as string); } - reply.headers({ [key]: [String(currentHeaders), value] }); + } else { + currentValues.add(value); + } + + appliedHeaders.set(key, currentValues); + } + + for (let [key, values] of appliedHeaders.entries()) { + if (values.size === 1) { + reply.header(key, values.values().next().value); continue; } - reply.headers({ [key]: value }); + + reply.header(key, [...values]); } if (nodeResponse.body) {