From b3a722f910ab6c3f4b9b60d4617af6dfb0077c3c Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Fri, 15 Nov 2024 19:02:45 -0500 Subject: [PATCH 01/13] feat: add react router entry point Signed-off-by: Logan McAnsh --- examples/playground/server.js | 4 +- ....timestamp-1731715104505-f49232386f5ef.mjs | 12 + examples/react-router/server.js | 6 +- packages/remix-fastify/package.json | 27 ++- packages/remix-fastify/react-router.cjs | 1 + packages/remix-fastify/react-router.d.cts | 1 + packages/remix-fastify/react-router.d.ts | 1 + packages/remix-fastify/react-router.js | 1 + packages/remix-fastify/remix.cjs | 1 + packages/remix-fastify/remix.d.cts | 1 + packages/remix-fastify/remix.d.ts | 1 + packages/remix-fastify/remix.js | 1 + packages/remix-fastify/src/index.ts | 10 +- .../src/{plugin.ts => plugins/index.ts} | 82 ++++--- .../remix-fastify/src/plugins/react-router.ts | 30 +++ packages/remix-fastify/src/plugins/remix.ts | 30 +++ packages/remix-fastify/src/react-router.ts | 12 + packages/remix-fastify/src/remix.ts | 12 + .../remix-fastify/src/servers/react-router.ts | 55 +++++ packages/remix-fastify/src/servers/remix.ts | 57 +++++ .../src/{server.ts => shared.ts} | 64 ++---- packages/remix-fastify/tsup.config.ts | 31 ++- pnpm-lock.yaml | 205 ++++++++++++------ render.yaml | 1 - 24 files changed, 481 insertions(+), 165 deletions(-) create mode 100644 examples/playground/vite.config.ts.timestamp-1731715104505-f49232386f5ef.mjs create mode 100644 packages/remix-fastify/react-router.cjs create mode 100644 packages/remix-fastify/react-router.d.cts create mode 100644 packages/remix-fastify/react-router.d.ts create mode 100644 packages/remix-fastify/react-router.js create mode 100644 packages/remix-fastify/remix.cjs create mode 100644 packages/remix-fastify/remix.d.cts create mode 100644 packages/remix-fastify/remix.d.ts create mode 100644 packages/remix-fastify/remix.js rename packages/remix-fastify/src/{plugin.ts => plugins/index.ts} (74%) create mode 100644 packages/remix-fastify/src/plugins/react-router.ts create mode 100644 packages/remix-fastify/src/plugins/remix.ts create mode 100644 packages/remix-fastify/src/react-router.ts create mode 100644 packages/remix-fastify/src/remix.ts create mode 100644 packages/remix-fastify/src/servers/react-router.ts create mode 100644 packages/remix-fastify/src/servers/remix.ts rename packages/remix-fastify/src/{server.ts => shared.ts} (71%) diff --git a/examples/playground/server.js b/examples/playground/server.js index 89006f58..279d6547 100644 --- a/examples/playground/server.js +++ b/examples/playground/server.js @@ -1,5 +1,5 @@ import chalk from "chalk"; -import { remixFastify } from "@mcansh/remix-fastify"; +import { reactRouterFastify } from "@mcansh/remix-fastify/react-router"; import { installGlobals } from "@remix-run/node"; import { fastify } from "fastify"; import sourceMapSupport from "source-map-support"; @@ -14,7 +14,7 @@ app.post("/api/echo", async (request, reply) => { reply.send(request.body); }); -await app.register(remixFastify, { +await app.register(reactRouterFastify, { getLoadContext(request, reply) { return { loadContextName: "Logan" }; }, diff --git a/examples/playground/vite.config.ts.timestamp-1731715104505-f49232386f5ef.mjs b/examples/playground/vite.config.ts.timestamp-1731715104505-f49232386f5ef.mjs new file mode 100644 index 00000000..dac114ce --- /dev/null +++ b/examples/playground/vite.config.ts.timestamp-1731715104505-f49232386f5ef.mjs @@ -0,0 +1,12 @@ +// vite.config.ts +import { vitePlugin as remix } from "file:///Users/lmcansh/remix-fastify/node_modules/.pnpm/@remix-run+dev@2.10.0_@remix-run+react@2.14.0_react-dom@19.0.0-rc-100dfd7dab-20240701_react@1_fdtw53wollluzaehojg7fjacfe/node_modules/@remix-run/dev/dist/index.js"; +import { defineConfig } from "file:///Users/lmcansh/remix-fastify/node_modules/.pnpm/vite@5.4.9_@types+node@22.7.7_lightningcss@1.26.0/node_modules/vite/dist/node/index.js"; +import tsconfigPaths from "file:///Users/lmcansh/remix-fastify/node_modules/.pnpm/vite-tsconfig-paths@5.0.1_typescript@5.6.3_vite@5.4.9_@types+node@22.7.7_lightningcss@1.26.0_/node_modules/vite-tsconfig-paths/dist/index.js"; +import tailwindcss from "file:///Users/lmcansh/remix-fastify/node_modules/.pnpm/@tailwindcss+vite@4.0.0-alpha.28_vite@5.4.9_@types+node@22.7.7_lightningcss@1.26.0_/node_modules/@tailwindcss/vite/dist/index.mjs"; +var vite_config_default = defineConfig({ + plugins: [remix(), tsconfigPaths(), tailwindcss()] +}); +export { + vite_config_default as default +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvVXNlcnMvbG1jYW5zaC9yZW1peC1mYXN0aWZ5L2V4YW1wbGVzL3BsYXlncm91bmRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9Vc2Vycy9sbWNhbnNoL3JlbWl4LWZhc3RpZnkvZXhhbXBsZXMvcGxheWdyb3VuZC92aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vVXNlcnMvbG1jYW5zaC9yZW1peC1mYXN0aWZ5L2V4YW1wbGVzL3BsYXlncm91bmQvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgeyB2aXRlUGx1Z2luIGFzIHJlbWl4IH0gZnJvbSBcIkByZW1peC1ydW4vZGV2XCI7XG5pbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tIFwidml0ZVwiO1xuaW1wb3J0IHRzY29uZmlnUGF0aHMgZnJvbSBcInZpdGUtdHNjb25maWctcGF0aHNcIjtcbmltcG9ydCB0YWlsd2luZGNzcyBmcm9tIFwiQHRhaWx3aW5kY3NzL3ZpdGVcIjtcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcbiAgcGx1Z2luczogW3JlbWl4KCksIHRzY29uZmlnUGF0aHMoKSwgdGFpbHdpbmRjc3MoKV0sXG59KTtcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBa1UsU0FBUyxjQUFjLGFBQWE7QUFDdFcsU0FBUyxvQkFBb0I7QUFDN0IsT0FBTyxtQkFBbUI7QUFDMUIsT0FBTyxpQkFBaUI7QUFFeEIsSUFBTyxzQkFBUSxhQUFhO0FBQUEsRUFDMUIsU0FBUyxDQUFDLE1BQU0sR0FBRyxjQUFjLEdBQUcsWUFBWSxDQUFDO0FBQ25ELENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg== diff --git a/examples/react-router/server.js b/examples/react-router/server.js index bb72cf8e..ce5b5f7a 100644 --- a/examples/react-router/server.js +++ b/examples/react-router/server.js @@ -1,5 +1,5 @@ import chalk from "chalk"; -import { remixFastify } from "@mcansh/remix-fastify"; +import { reactRouterFastify } from "@mcansh/remix-fastify/react-router"; import { fastify } from "fastify"; import sourceMapSupport from "source-map-support"; import getPort, { portNumbers } from "get-port"; @@ -8,9 +8,7 @@ sourceMapSupport.install(); let app = fastify(); -await app.register(remixFastify, { - virtualModule: "virtual:react-router/server-build", -}); +await app.register(reactRouterFastify); const desiredPort = Number(process.env.PORT) || 3000; const portToUse = await getPort({ diff --git a/packages/remix-fastify/package.json b/packages/remix-fastify/package.json index c061b92a..9b96c655 100644 --- a/packages/remix-fastify/package.json +++ b/packages/remix-fastify/package.json @@ -1,7 +1,7 @@ { "name": "@mcansh/remix-fastify", "version": "4.0.1", - "description": "Fastify server request handler for Remix", + "description": "Fastify server request handler for Remix and React Router", "repository": "mcansh/remix-fastify", "license": "MIT", "author": "Logan McAnsh (https://mcan.sh)", @@ -11,6 +11,7 @@ "keywords": [ "remix", "remix-run", + "react-router", "fastify" ], "funding": [ @@ -25,6 +26,14 @@ ".": { "require": "./dist/index.cjs", "import": "./dist/index.js" + }, + "./react-router": { + "require": "./dist/react-router.cjs", + "import": "./dist/react-router.js" + }, + "./remix": { + "require": "./dist/remix.cjs", + "import": "./dist/remix.js" } }, "main": "./dist/index.cjs", @@ -35,10 +44,18 @@ "dist", "package.json", "README.md", - "LICENSE" + "LICENSE", + "react-router.cjs", + "react-router.d.cts", + "react-router.d.ts", + "react-router.js", + "remix.cjs", + "remix.d.cts", + "remix.d.ts", + "remix.js" ], "scripts": { - "prepublishOnly": "npm run build && cp ../../LICENSE LICENSE && publint && attw $(npm pack)", + "prepublishOnly": "npm run build && cp ../../LICENSE LICENSE && publint && attw --pack", "typecheck": "tsc", "dev": "tsup --watch", "build": "tsup", @@ -52,18 +69,20 @@ "pretty-cache-header": "^1.0.0" }, "devDependencies": { + "@react-router/node": "7.0.0-pre.5", "@remix-run/node": "^2.13.1", "@types/node": "^22.7.7", "@typescript/lib-dom": "npm:@types/web@^0.0.174", "fastify": "^5.0.0", "node-mocks-http": "^1.16.1", + "react-router": "^7.0.0-pre.5", "typescript": "^5.6.3", "vite": "^5.4.9" }, "peerDependencies": { "@remix-run/node": "^2.0.0", "fastify": "^3.29.0 || ^4.0.0 || ^5.0.0", - "react-router": "*", + "react-router": ">=7.0.0 || >=7.0.0.pre", "vite": "^5.0.0" }, "peerDependenciesMeta": { diff --git a/packages/remix-fastify/react-router.cjs b/packages/remix-fastify/react-router.cjs new file mode 100644 index 00000000..47ee9f5e --- /dev/null +++ b/packages/remix-fastify/react-router.cjs @@ -0,0 +1 @@ +module.exports = require("./dist/react-router"); \ No newline at end of file diff --git a/packages/remix-fastify/react-router.d.cts b/packages/remix-fastify/react-router.d.cts new file mode 100644 index 00000000..7a56c995 --- /dev/null +++ b/packages/remix-fastify/react-router.d.cts @@ -0,0 +1 @@ +export type * from "./dist/react-router"; \ No newline at end of file diff --git a/packages/remix-fastify/react-router.d.ts b/packages/remix-fastify/react-router.d.ts new file mode 100644 index 00000000..7a56c995 --- /dev/null +++ b/packages/remix-fastify/react-router.d.ts @@ -0,0 +1 @@ +export type * from "./dist/react-router"; \ No newline at end of file diff --git a/packages/remix-fastify/react-router.js b/packages/remix-fastify/react-router.js new file mode 100644 index 00000000..ecf83428 --- /dev/null +++ b/packages/remix-fastify/react-router.js @@ -0,0 +1 @@ +export * from "./dist/react-router"; \ No newline at end of file diff --git a/packages/remix-fastify/remix.cjs b/packages/remix-fastify/remix.cjs new file mode 100644 index 00000000..a76c0656 --- /dev/null +++ b/packages/remix-fastify/remix.cjs @@ -0,0 +1 @@ +module.exports = require("./dist/remix"); \ No newline at end of file diff --git a/packages/remix-fastify/remix.d.cts b/packages/remix-fastify/remix.d.cts new file mode 100644 index 00000000..862ee82f --- /dev/null +++ b/packages/remix-fastify/remix.d.cts @@ -0,0 +1 @@ +export type * from "./dist/remix"; \ No newline at end of file diff --git a/packages/remix-fastify/remix.d.ts b/packages/remix-fastify/remix.d.ts new file mode 100644 index 00000000..862ee82f --- /dev/null +++ b/packages/remix-fastify/remix.d.ts @@ -0,0 +1 @@ +export type * from "./dist/remix"; \ No newline at end of file diff --git a/packages/remix-fastify/remix.js b/packages/remix-fastify/remix.js new file mode 100644 index 00000000..f3a40695 --- /dev/null +++ b/packages/remix-fastify/remix.js @@ -0,0 +1 @@ +export * from "./dist/remix"; \ No newline at end of file diff --git a/packages/remix-fastify/src/index.ts b/packages/remix-fastify/src/index.ts index 1079e0a7..f38a0d93 100644 --- a/packages/remix-fastify/src/index.ts +++ b/packages/remix-fastify/src/index.ts @@ -1,4 +1,6 @@ -export type { GetLoadContextFunction, RequestHandler } from "./server"; -export { createRequestHandler } from "./server"; -export { remixFastify } from "./plugin"; -export type { RemixFastifyOptions } from "./plugin"; +export type { + GetLoadContextFunction, + RequestHandler, + RemixFastifyOptions, +} from "./remix"; +export { createRequestHandler, remixFastify } from "./remix"; diff --git a/packages/remix-fastify/src/plugin.ts b/packages/remix-fastify/src/plugins/index.ts similarity index 74% rename from packages/remix-fastify/src/plugin.ts rename to packages/remix-fastify/src/plugins/index.ts index bcadb0ba..ea0b80b0 100644 --- a/packages/remix-fastify/src/plugin.ts +++ b/packages/remix-fastify/src/plugins/index.ts @@ -1,15 +1,19 @@ +import type { FastifyInstance } from "fastify"; + import path from "node:path"; import url from "node:url"; -import fp from "fastify-plugin"; import type { InlineConfig, ViteDevServer } from "vite"; import fastifyStatic, { type FastifyStaticOptions } from "@fastify/static"; import { cacheHeader } from "pretty-cache-header"; -import type { ServerBuild } from "@remix-run/node"; - -import { createRequestHandler } from "./server"; -import type { HttpServer, GetLoadContextFunction } from "./server"; +import type { GetLoadContextFunction, HttpServer } from "../shared"; +import type { CreateRequestHandlerFunction as RRCreateRequestHandlerFunction } from "../servers/react-router"; +import type { CreateRequestHandlerFunction as RemixCreateRequestHandlerFunction } from "../servers/remix"; -export type RemixFastifyOptions = { +export type PluginOptions< + Server extends HttpServer = HttpServer, + AppLoadContext = unknown, + ServerBuild = unknown, +> = { /** * The base path for the Remix app. * match the `basename` in your Vite config. @@ -35,7 +39,7 @@ export type RemixFastifyOptions = { * You can think of this as an escape hatch that allows you to pass * environment/platform-specific values through to your loader/action. */ - getLoadContext?: GetLoadContextFunction; + getLoadContext: GetLoadContextFunction; mode?: string; /** * Options to pass to the Vite server in development. @@ -67,28 +71,40 @@ export type RemixFastifyOptions = { productionServerBuild?: | ServerBuild | (() => ServerBuild | Promise); - virtualModule?: + + /** + * The virtual module to load in development. + */ + virtualModule: | "virtual:remix/server-build" | "virtual:react-router/server-build"; }; -export const remixFastify = fp( - async ( - fastify, - { - basename = "/", - buildDirectory = "build", - serverBuildFile = "index.js", - getLoadContext, - mode = process.env.NODE_ENV, - viteOptions, - fastifyStaticOptions, - assetCacheControl = { public: true, maxAge: "1 year", immutable: true }, - defaultCacheControl = { public: true, maxAge: "1 hour" }, - productionServerBuild, - virtualModule = "virtual:remix/server-build", - }, - ) => { +export function createPlugin( + fastify: FastifyInstance, + { + basename = "/", + buildDirectory = "build", + serverBuildFile = "index.js", + getLoadContext, + mode = process.env.NODE_ENV, + viteOptions, + fastifyStaticOptions, + assetCacheControl = { public: true, maxAge: "1 year", immutable: true }, + defaultCacheControl = { public: true, maxAge: "1 hour" }, + productionServerBuild, + virtualModule, + }: PluginOptions, + // TODO: look if importing the function as a type requires the peer dependency + createRequestHandler: + | RemixCreateRequestHandlerFunction + | RRCreateRequestHandlerFunction, +) { + console.log(`inside createPlugin`); + + return async () => { + console.log(`inside createPlugin async`); + let cwd = process.env.REMIX_ROOT ?? process.cwd(); let vite: ViteDevServer | undefined; @@ -113,9 +129,11 @@ export const remixFastify = fp( ); let SERVER_BUILD_URL = url.pathToFileURL(SERVER_BUILD).href; - let remixHandler = createRequestHandler({ + let handler = createRequestHandler({ mode, + // @ts-expect-error - fix this getLoadContext, + // @ts-expect-error - fix this build: vite ? () => vite.ssrLoadModule(virtualModule) : (productionServerBuild ?? (() => import(SERVER_BUILD_URL))), @@ -139,6 +157,7 @@ export const remixFastify = fp( serveDotFiles: true, lastModified: true, setHeaders(res, filepath) { + console.log({ filepath }); let isAsset = filepath.startsWith(ASSET_DIR); res.setHeader( "cache-control", @@ -161,15 +180,10 @@ export const remixFastify = fp( }); childServer.all("*", (request, reply) => { - remixHandler(request, reply); + handler(request, reply); }); }, { prefix: basename }, ); - }, - { - // replaced with the package name during build - name: process.env.__PACKAGE_NAME__, - fastify: process.env.__FASTIFY_VERSION__, - }, -); + }; +} diff --git a/packages/remix-fastify/src/plugins/react-router.ts b/packages/remix-fastify/src/plugins/react-router.ts new file mode 100644 index 00000000..bb30a9dd --- /dev/null +++ b/packages/remix-fastify/src/plugins/react-router.ts @@ -0,0 +1,30 @@ +import fp from "fastify-plugin"; + +import type { HttpServer } from "../shared"; +import type { AppLoadContext, ServerBuild } from "react-router"; +import { createRequestHandler } from "../servers/react-router"; +import { createPlugin, type PluginOptions } from "."; + +export type ReactRouterFastifyOptions = Omit< + PluginOptions, + "virtualModule" +>; + +export const reactRouterFastify = fp( + async (fastify, options) => { + let plugin = createPlugin( + fastify, + { + ...options, + virtualModule: "virtual:react-router/server-build", + }, + createRequestHandler, + ); + return plugin(); + }, + { + // replaced with the package name during build + name: process.env.__PACKAGE_NAME__, + fastify: process.env.__FASTIFY_VERSION__, + }, +); diff --git a/packages/remix-fastify/src/plugins/remix.ts b/packages/remix-fastify/src/plugins/remix.ts new file mode 100644 index 00000000..de4e5b64 --- /dev/null +++ b/packages/remix-fastify/src/plugins/remix.ts @@ -0,0 +1,30 @@ +import fp from "fastify-plugin"; +import type { AppLoadContext, ServerBuild } from "@remix-run/node"; + +import { createRequestHandler } from "../servers/remix"; +import type { HttpServer } from "../shared"; +import { createPlugin, type PluginOptions } from "."; + +export type RemixFastifyOptions = Omit< + PluginOptions, + "virtualModule" +>; + +export const remixFastify = fp( + async (fastify, options) => { + let plugin = createPlugin( + fastify, + { + ...options, + virtualModule: "virtual:remix/server-build", + }, + createRequestHandler, + ); + return plugin(); + }, + { + // replaced with the package name during build + name: process.env.__PACKAGE_NAME__, + fastify: process.env.__FASTIFY_VERSION__, + }, +); diff --git a/packages/remix-fastify/src/react-router.ts b/packages/remix-fastify/src/react-router.ts new file mode 100644 index 00000000..8c396db9 --- /dev/null +++ b/packages/remix-fastify/src/react-router.ts @@ -0,0 +1,12 @@ +import type { AppLoadContext } from "react-router"; +import type { + HttpServer, + GetLoadContextFunction as SharedGetLoadContextFunction, +} from "./shared"; +export type { RequestHandler } from "./shared"; +export { createRequestHandler } from "./servers/react-router"; +export { reactRouterFastify } from "./plugins/react-router"; +export type { ReactRouterFastifyOptions } from "./plugins/react-router"; + +export type GetLoadContextFunction = + SharedGetLoadContextFunction; diff --git a/packages/remix-fastify/src/remix.ts b/packages/remix-fastify/src/remix.ts new file mode 100644 index 00000000..05f3f039 --- /dev/null +++ b/packages/remix-fastify/src/remix.ts @@ -0,0 +1,12 @@ +import type { AppLoadContext } from "@remix-run/node"; +import type { + HttpServer, + GetLoadContextFunction as SharedGetLoadContextFunction, +} from "./shared"; +export type { RequestHandler } from "./shared"; +export { createRequestHandler } from "./servers/remix"; +export { remixFastify } from "./plugins/remix"; +export type { RemixFastifyOptions } from "./plugins/remix"; + +export type GetLoadContextFunction = + SharedGetLoadContextFunction; diff --git a/packages/remix-fastify/src/servers/react-router.ts b/packages/remix-fastify/src/servers/react-router.ts new file mode 100644 index 00000000..c7bdf71d --- /dev/null +++ b/packages/remix-fastify/src/servers/react-router.ts @@ -0,0 +1,55 @@ +import type { + FastifyRequest, + FastifyReply, + RouteGenericInterface, +} from "fastify"; +import { createRequestHandler as createRemixRequestHandler } from "react-router"; +import type { AppLoadContext, ServerBuild } from "react-router"; +import { createReadableStreamFromReadable } from "@react-router/node"; +import { createRequestInit, getUrl, sendResponse } from "../shared"; +import type { + HttpServer, + RequestHandler, + GetLoadContextFunction as GenericGetLoadContextFunction, +} from "../shared"; + +export type CreateRequestHandlerFunction = typeof createRequestHandler; +export type GetLoadContextFunction = + GenericGetLoadContextFunction; + +/** + * Returns a request handler for Fastify that serves the response using Remix. + */ +export function createRequestHandler({ + build, + getLoadContext, + mode = process.env.NODE_ENV, +}: { + build: ServerBuild | (() => ServerBuild | Promise); + getLoadContext?: GetLoadContextFunction; + mode?: string; +}): RequestHandler { + let handleRequest = createRemixRequestHandler(build, mode); + + return async (request, reply) => { + let remixRequest = createRequest(request, reply); + let loadContext = await getLoadContext?.(request, reply); + let response = await handleRequest(remixRequest, loadContext); + return sendResponse(reply, response); + }; +} + +function createRequest( + request: FastifyRequest, + reply: FastifyReply, +): Request { + let url = getUrl(request); + let init = createRequestInit(request, reply); + + if (request.method !== "GET" && request.method !== "HEAD") { + init.body = createReadableStreamFromReadable(request.raw); + init.duplex = "half"; + } + + return new Request(url, init); +} diff --git a/packages/remix-fastify/src/servers/remix.ts b/packages/remix-fastify/src/servers/remix.ts new file mode 100644 index 00000000..3d0150c7 --- /dev/null +++ b/packages/remix-fastify/src/servers/remix.ts @@ -0,0 +1,57 @@ +import type { + FastifyRequest, + FastifyReply, + RouteGenericInterface, +} from "fastify"; +import type { AppLoadContext, ServerBuild } from "@remix-run/node"; +import { + createRequestHandler as createRemixRequestHandler, + createReadableStreamFromReadable, +} from "@remix-run/node"; +import { createRequestInit, getUrl, sendResponse } from "../shared"; +import type { + GetLoadContextFunction as GenericGetLoadContextFunction, + HttpServer, + RequestHandler, +} from "../shared"; + +export type CreateRequestHandlerFunction = typeof createRequestHandler; +export type GetLoadContextFunction = + GenericGetLoadContextFunction; + +/** + * Returns a request handler for Fastify that serves the response using Remix. + */ +export function createRequestHandler({ + build, + getLoadContext, + mode = process.env.NODE_ENV, +}: { + build: ServerBuild | (() => ServerBuild | Promise); + getLoadContext?: GetLoadContextFunction; + mode?: string; +}): RequestHandler { + let handleRequest = createRemixRequestHandler(build, mode); + + return async (request, reply) => { + let remixRequest = createRequest(request, reply); + let loadContext = await getLoadContext?.(request, reply); + let response = await handleRequest(remixRequest, loadContext); + return sendResponse(reply, response); + }; +} + +function createRequest( + request: FastifyRequest, + reply: FastifyReply, +): Request { + let url = getUrl(request); + let init = createRequestInit(request, reply); + + if (request.method !== "GET" && request.method !== "HEAD") { + init.body = createReadableStreamFromReadable(request.raw); + init.duplex = "half"; + } + + return new Request(url, init); +} diff --git a/packages/remix-fastify/src/server.ts b/packages/remix-fastify/src/shared.ts similarity index 71% rename from packages/remix-fastify/src/server.ts rename to packages/remix-fastify/src/shared.ts index 3b900faa..ce2eb600 100644 --- a/packages/remix-fastify/src/server.ts +++ b/packages/remix-fastify/src/shared.ts @@ -3,17 +3,12 @@ import type * as http from "node:http"; import type * as http2 from "node:http2"; import type * as https from "node:https"; import type { - FastifyRequest, FastifyReply, - RawRequestDefaultExpression, + FastifyRequest, RawReplyDefaultExpression, + RawRequestDefaultExpression, RouteGenericInterface, } from "fastify"; -import type { AppLoadContext, ServerBuild } from "@remix-run/node"; -import { - createRequestHandler as createRemixRequestHandler, - createReadableStreamFromReadable, -} from "@remix-run/node"; export type HttpServer = | http.Server @@ -24,6 +19,11 @@ export type HttpServer = export type HttpRequest = RawRequestDefaultExpression; export type HttpResponse = RawReplyDefaultExpression; +export type RequestHandler = ( + request: FastifyRequest, + reply: FastifyReply, +) => Promise; + /** * A function that returns the value to use as `context` in route `loader` and * `action` functions. @@ -31,40 +31,14 @@ export type HttpResponse = RawReplyDefaultExpression; * You can think of this as an escape hatch that allows you to pass * environment/platform-specific values through to your loader/action. */ -export type GetLoadContextFunction = ( +export type GetLoadContextFunction< + Server extends HttpServer, + AppLoadContext, +> = ( request: FastifyRequest, reply: FastifyReply, ) => Promise | AppLoadContext; -export type RequestHandler = ( - request: FastifyRequest, - reply: FastifyReply, -) => Promise; - -/** - * Returns a request handler for Fastify that serves the response using Remix. - */ -export function createRequestHandler({ - build, - getLoadContext, - mode = process.env.NODE_ENV, -}: { - build: ServerBuild | (() => ServerBuild | Promise); - getLoadContext?: GetLoadContextFunction; - mode?: string; -}): RequestHandler { - let handleRequest = createRemixRequestHandler(build, mode); - - return async (request, reply) => { - let remixRequest = createRemixRequest(request, reply); - let loadContext = await getLoadContext?.(request, reply); - - let response = await handleRequest(remixRequest, loadContext); - - return sendRemixResponse(reply, response); - }; -} - export function createRemixHeaders( requestHeaders: FastifyRequest["headers"], ): Headers { @@ -94,12 +68,10 @@ export function getUrl( return url; } -export function createRemixRequest( +export function createRequestInit( request: FastifyRequest, reply: FastifyReply, -): Request { - let url = getUrl(request); - +): RequestInit { let controller: AbortController | null = new AbortController(); let init: RequestInit = { @@ -115,15 +87,10 @@ export function createRemixRequest( reply.raw.on("finish", () => (controller = null)); reply.raw.on("close", () => controller?.abort()); - if (request.method !== "GET" && request.method !== "HEAD") { - init.body = createReadableStreamFromReadable(request.raw); - init.duplex = "half"; - } - - return new Request(url, init); + return init; } -export async function sendRemixResponse( +export async function sendResponse( reply: FastifyReply, nodeResponse: Response, ): Promise { @@ -152,7 +119,6 @@ function responseToReadable(response: Response): Readable | null { readable.push(Buffer.from(result.value)); } else { readable.push(null); - return; } }; diff --git a/packages/remix-fastify/tsup.config.ts b/packages/remix-fastify/tsup.config.ts index bd523861..ab514f00 100644 --- a/packages/remix-fastify/tsup.config.ts +++ b/packages/remix-fastify/tsup.config.ts @@ -1,16 +1,24 @@ +import Fsp from "node:fs/promises"; +import Path from "node:path"; import { defineConfig } from "tsup"; import pkg from "./package.json"; export default defineConfig(() => { return { - entry: ["src/index.ts"], + entry: { + index: "./src/index.ts", + remix: "./src/remix.ts", + "react-router": "./src/react-router.ts", + }, sourcemap: true, tsconfig: "./tsconfig.json", dts: true, + clean: true, format: ["cjs", "esm"], cjsInterop: true, - splitting: true, + splitting: false, + bundle: true, platform: "node", skipNodeModulesBundle: true, treeshake: true, @@ -20,5 +28,24 @@ export default defineConfig(() => { pkg.peerDependencies.fastify, ), }, + async onSuccess() { + let subPaths = ["remix", "react-router"]; + + // generate root re-exports for each sub-path + for (let subPath of subPaths) { + let cjs = js`module.exports = require("./dist/${subPath}");`; + let esm = js`export * from "./dist/${subPath}";`; + let dts = js`export type * from "./dist/${subPath}";`; + + await Promise.all([ + Fsp.writeFile(`${subPath}.cjs`, cjs), + Fsp.writeFile(`${subPath}.js`, esm), + Fsp.writeFile(`${subPath}.d.ts`, dts), + Fsp.writeFile(`${subPath}.d.cts`, dts), + ]); + } + }, }; }); + +let js = String.raw; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d379f23..353a4062 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,7 +24,7 @@ importers: version: 6.0.1 '@remix-run/eslint-config': specifier: latest - version: 2.13.1(eslint@9.13.0(jiti@2.3.3))(react@18.3.1)(typescript@5.6.3) + version: 2.14.0(eslint@9.13.0(jiti@2.3.3))(react@18.3.1)(typescript@5.6.3) '@types/npmcli__package-json': specifier: ^4.0.4 version: 4.0.4 @@ -90,13 +90,13 @@ importers: version: link:../../packages/remix-fastify '@remix-run/css-bundle': specifier: latest - version: 2.13.1 + version: 2.14.0 '@remix-run/node': specifier: latest - version: 2.13.1(typescript@5.6.3) + version: 2.14.0(typescript@5.6.3) '@remix-run/react': specifier: latest - version: 2.13.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + version: 2.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) chalk: specifier: ^5.3.0 version: 5.3.0 @@ -124,7 +124,7 @@ importers: devDependencies: '@remix-run/dev': specifier: '*' - version: 2.9.0(@remix-run/react@2.13.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@types/node@22.7.7)(lightningcss@1.26.0)(ts-node@10.9.2(@types/node@22.7.7)(typescript@5.6.3))(typescript@5.6.3)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0)) + version: 2.9.0(@remix-run/react@2.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@types/node@22.7.7)(lightningcss@1.26.0)(ts-node@10.9.2(@types/node@22.7.7)(typescript@5.6.3))(typescript@5.6.3)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0)) '@remix-run/eslint-config': specifier: '*' version: 2.9.0(eslint@8.57.0)(react@18.3.1)(typescript@5.6.3) @@ -157,10 +157,10 @@ importers: version: link:../../packages/remix-fastify '@remix-run/node': specifier: latest - version: 2.13.1(typescript@5.6.3) + version: 2.14.0(typescript@5.6.3) '@remix-run/react': specifier: latest - version: 2.13.1(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701)(typescript@5.6.3) + version: 2.14.0(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701)(typescript@5.6.3) chalk: specifier: ^5.3.0 version: 5.3.0 @@ -188,7 +188,7 @@ importers: version: 9.0.2 '@remix-run/dev': specifier: '*' - version: 2.10.0(@remix-run/react@2.13.1(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701)(typescript@5.6.3))(@types/node@22.7.7)(lightningcss@1.26.0)(ts-node@10.9.2(@types/node@22.7.7)(typescript@5.6.3))(typescript@5.6.3)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0)) + version: 2.10.0(@remix-run/react@2.14.0(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701)(typescript@5.6.3))(@types/node@22.7.7)(lightningcss@1.26.0)(ts-node@10.9.2(@types/node@22.7.7)(typescript@5.6.3))(typescript@5.6.3)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0)) '@remix-run/eslint-config': specifier: '*' version: 2.9.0(eslint@8.57.0)(react@19.0.0-rc-100dfd7dab-20240701)(typescript@5.6.3) @@ -318,13 +318,13 @@ importers: version: link:../../packages/remix-fastify '@remix-run/node': specifier: latest - version: 2.13.1(typescript@5.6.3) + version: 2.14.0(typescript@5.6.3) '@remix-run/react': specifier: latest - version: 2.13.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + version: 2.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@remix-run/server-runtime': specifier: latest - version: 2.13.1(typescript@5.6.3) + version: 2.14.0(typescript@5.6.3) chalk: specifier: ^5.3.0 version: 5.3.0 @@ -352,7 +352,7 @@ importers: devDependencies: '@remix-run/dev': specifier: '*' - version: 2.9.0(@remix-run/react@2.13.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@types/node@22.7.7)(lightningcss@1.26.0)(ts-node@10.9.2(@types/node@22.7.7)(typescript@5.6.3))(typescript@5.6.3)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0)) + version: 2.9.0(@remix-run/react@2.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@types/node@22.7.7)(lightningcss@1.26.0)(ts-node@10.9.2(@types/node@22.7.7)(typescript@5.6.3))(typescript@5.6.3)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0)) '@remix-run/eslint-config': specifier: '*' version: 2.9.0(eslint@8.57.0)(react@18.3.1)(typescript@5.6.3) @@ -398,10 +398,10 @@ importers: pretty-cache-header: specifier: ^1.0.0 version: 1.0.0 - react-router: - specifier: '*' - version: 6.27.0(react@19.0.0-rc-100dfd7dab-20240701) devDependencies: + '@react-router/node': + specifier: 7.0.0-pre.5 + version: 7.0.0-pre.5(react-router@7.0.0-pre.5(react-dom@18.3.1(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701))(typescript@5.6.3) '@remix-run/node': specifier: ^2.13.1 version: 2.13.1(typescript@5.6.3) @@ -417,6 +417,9 @@ importers: node-mocks-http: specifier: ^1.16.1 version: 1.16.1(@types/express@4.17.21)(@types/node@22.7.7) + react-router: + specifier: ^7.0.0-pre.5 + version: 7.0.0-pre.5(react-dom@18.3.1(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701) typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1696,6 +1699,16 @@ packages: typescript: optional: true + '@react-router/node@7.0.0-pre.5': + resolution: {integrity: sha512-meYaoDNs2F31v6BRGFikPCtoJ0VZfi7MTdlooc1wgxD/uO+GcV2i3RPLrvt2hXyDE59guz62Q73h+SiUlFMfeA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react-router: 7.0.0-pre.5 + typescript: ^5.1.0 + peerDependenciesMeta: + typescript: + optional: true + '@react-router/serve@7.0.0-pre.4': resolution: {integrity: sha512-Zh76x3X20PU7vt0t2DADsQxvpjcLxY29pJ/nF/uPG1KU+MwWM/EuQfIHWvKjng9FnlCgTKzYMjUu8essQpZKaw==} engines: {node: '>=20.0.0'} @@ -1703,8 +1716,8 @@ packages: peerDependencies: react-router: 7.0.0-pre.4 - '@remix-run/css-bundle@2.13.1': - resolution: {integrity: sha512-ukams+HcEaovitySAmH2Q8Gg8c6A3fKr5RJEpAn0NYk1Cc2t0fH05GVAGToOgtWeFeOUjREXAqk3+C76o0cHkg==} + '@remix-run/css-bundle@2.14.0': + resolution: {integrity: sha512-ihdLzO3UUAbdTkBQ/jl9rEmhFKzUA8eEAvvpjdkumipoKkiOsjqAFV62FAMf7mrKNBCv7UeoIOm6XHV9Io2DZg==} engines: {node: '>=18.0.0'} '@remix-run/dev@2.10.0': @@ -1747,9 +1760,10 @@ packages: wrangler: optional: true - '@remix-run/eslint-config@2.13.1': - resolution: {integrity: sha512-UNWRHYa++pWrO6qxNI9z7KrmD0/wncWjS36TujoPmlnVDQ2pKIhNZwBi6otJQIuI8TdUPBZstJNgRJ0TWYok6A==} + '@remix-run/eslint-config@2.14.0': + resolution: {integrity: sha512-/wBt/AVgBMNw8HWifSha/7dwaGudmyWo7FB7M+LKloZPZc+XR60cMqKSXJeWwJTo+pic++4V1GhQnKc+Cx3GyA==} engines: {node: '>=18.0.0'} + deprecated: Will no longer be maintained in React Router v7 peerDependencies: eslint: ^8.0.0 react: ^18.0.0 @@ -1761,6 +1775,7 @@ packages: '@remix-run/eslint-config@2.9.0': resolution: {integrity: sha512-y86wPR+l/SlhSoobs2RPeuRIP0OJ3wKZNpGDtId+QN7Kc3XswZipAxBlVspTk23x8aweNOSqoqMI0xfEkrGt5Q==} engines: {node: '>=18.0.0'} + deprecated: Will no longer be maintained in React Router v7 peerDependencies: eslint: ^8.0.0 react: ^18.0.0 @@ -1778,8 +1793,17 @@ packages: typescript: optional: true - '@remix-run/react@2.13.1': - resolution: {integrity: sha512-kZevCoKMz0ZDOOzTnG95yfM7M9ju38FkWNY1wtxCy+NnUJYrmTerGQtiBsJgMzYD6i29+w4EwoQsdqys7DmMSg==} + '@remix-run/node@2.14.0': + resolution: {integrity: sha512-ou16LMJYv0ElIToZ6dDqaLjv1T3iBEwuJTBahveEA8NkkACIWODJ2fgUYf1UKLMKHVdHjNImLzS37HdSZY0Q6g==} + engines: {node: '>=18.0.0'} + peerDependencies: + typescript: ^5.1.0 + peerDependenciesMeta: + typescript: + optional: true + + '@remix-run/react@2.14.0': + resolution: {integrity: sha512-uQcy5gxazHtpislgonx2dwRuR/CbvYUeguQxDgawd+dAyoglK2rFx58+F6Kj0Vjw6v/iuvxibA/lEAiAaB4ZmQ==} engines: {node: '>=18.0.0'} peerDependencies: react: ^18.0.0 @@ -1789,12 +1813,12 @@ packages: typescript: optional: true - '@remix-run/router@1.20.0': - resolution: {integrity: sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==} + '@remix-run/router@1.21.0': + resolution: {integrity: sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==} engines: {node: '>=14.0.0'} - '@remix-run/server-runtime@2.13.1': - resolution: {integrity: sha512-2DfBPRcHKVzE4bCNsNkKB50BhCCKF73x+jiS836OyxSIAL+x0tguV2AEjmGXefEXc5AGGzoxkus0AUUEYa29Vg==} + '@remix-run/server-runtime@2.14.0': + resolution: {integrity: sha512-9Th9UzDaoFFBD7zA5mRI1KT8JktFLN4ij9jPygrKBhG/kYmNIvhcMtq9VyjcbMvFK5natTyhOhrrKRIHtijD4w==} engines: {node: '>=18.0.0'} peerDependencies: typescript: ^5.1.0 @@ -5448,15 +5472,15 @@ packages: resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} engines: {node: '>=0.10.0'} - react-router-dom@6.27.0: - resolution: {integrity: sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==} + react-router-dom@6.28.0: + resolution: {integrity: sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' react-dom: '>=16.8' - react-router@6.27.0: - resolution: {integrity: sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==} + react-router@6.28.0: + resolution: {integrity: sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' @@ -5471,6 +5495,16 @@ packages: react-dom: optional: true + react-router@7.0.0-pre.5: + resolution: {integrity: sha512-UGrqwmlTubhrtUzIu1WYb1z9FVeCqGi9RdywwjFrSQqIDTPjn7g5PPuFAS6pbVuj81VRI7HVzaljpzKXPDnfEQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -7958,6 +7992,16 @@ snapshots: optionalDependencies: typescript: 5.6.3 + '@react-router/node@7.0.0-pre.5(react-router@7.0.0-pre.5(react-dom@18.3.1(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701))(typescript@5.6.3)': + dependencies: + '@web3-storage/multipart-parser': 1.0.0 + react-router: 7.0.0-pre.5(react-dom@18.3.1(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701) + source-map-support: 0.5.21 + stream-slice: 0.1.2 + undici: 6.20.1 + optionalDependencies: + typescript: 5.6.3 + '@react-router/serve@7.0.0-pre.4(react-router@7.0.0-pre.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.3)': dependencies: '@react-router/express': 7.0.0-pre.4(express@4.19.2)(react-router@7.0.0-pre.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.3) @@ -7972,9 +8016,9 @@ snapshots: - supports-color - typescript - '@remix-run/css-bundle@2.13.1': {} + '@remix-run/css-bundle@2.14.0': {} - '@remix-run/dev@2.10.0(@remix-run/react@2.13.1(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701)(typescript@5.6.3))(@types/node@22.7.7)(lightningcss@1.26.0)(ts-node@10.9.2(@types/node@22.7.7)(typescript@5.6.3))(typescript@5.6.3)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0))': + '@remix-run/dev@2.10.0(@remix-run/react@2.14.0(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701)(typescript@5.6.3))(@types/node@22.7.7)(lightningcss@1.26.0)(ts-node@10.9.2(@types/node@22.7.7)(typescript@5.6.3))(typescript@5.6.3)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0))': dependencies: '@babel/core': 7.24.0 '@babel/generator': 7.23.6 @@ -7986,10 +8030,10 @@ snapshots: '@babel/types': 7.24.0 '@mdx-js/mdx': 2.3.0 '@npmcli/package-json': 4.0.1 - '@remix-run/node': 2.13.1(typescript@5.6.3) - '@remix-run/react': 2.13.1(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701)(typescript@5.6.3) - '@remix-run/router': 1.20.0 - '@remix-run/server-runtime': 2.13.1(typescript@5.6.3) + '@remix-run/node': 2.14.0(typescript@5.6.3) + '@remix-run/react': 2.14.0(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701)(typescript@5.6.3) + '@remix-run/router': 1.21.0 + '@remix-run/server-runtime': 2.14.0(typescript@5.6.3) '@types/mdx': 2.0.11 '@vanilla-extract/integration': 6.5.0(@types/node@22.7.7)(lightningcss@1.26.0) arg: 5.0.2 @@ -8048,7 +8092,7 @@ snapshots: - ts-node - utf-8-validate - '@remix-run/dev@2.9.0(@remix-run/react@2.13.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@types/node@22.7.7)(lightningcss@1.26.0)(ts-node@10.9.2(@types/node@22.7.7)(typescript@5.6.3))(typescript@5.6.3)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0))': + '@remix-run/dev@2.9.0(@remix-run/react@2.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@types/node@22.7.7)(lightningcss@1.26.0)(ts-node@10.9.2(@types/node@22.7.7)(typescript@5.6.3))(typescript@5.6.3)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0))': dependencies: '@babel/core': 7.24.0 '@babel/generator': 7.23.6 @@ -8060,10 +8104,10 @@ snapshots: '@babel/types': 7.24.0 '@mdx-js/mdx': 2.3.0 '@npmcli/package-json': 4.0.1 - '@remix-run/node': 2.13.1(typescript@5.6.3) - '@remix-run/react': 2.13.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@remix-run/router': 1.20.0 - '@remix-run/server-runtime': 2.13.1(typescript@5.6.3) + '@remix-run/node': 2.14.0(typescript@5.6.3) + '@remix-run/react': 2.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@remix-run/router': 1.21.0 + '@remix-run/server-runtime': 2.14.0(typescript@5.6.3) '@types/mdx': 2.0.11 '@vanilla-extract/integration': 6.5.0(@types/node@22.7.7)(lightningcss@1.26.0) arg: 5.0.2 @@ -8122,7 +8166,7 @@ snapshots: - ts-node - utf-8-validate - '@remix-run/eslint-config@2.13.1(eslint@9.13.0(jiti@2.3.3))(react@18.3.1)(typescript@5.6.3)': + '@remix-run/eslint-config@2.14.0(eslint@9.13.0(jiti@2.3.3))(react@18.3.1)(typescript@5.6.3)': dependencies: '@babel/core': 7.25.8 '@babel/eslint-parser': 7.25.8(@babel/core@7.25.8)(eslint@9.13.0(jiti@2.3.3)) @@ -8206,7 +8250,19 @@ snapshots: '@remix-run/node@2.13.1(typescript@5.6.3)': dependencies: - '@remix-run/server-runtime': 2.13.1(typescript@5.6.3) + '@remix-run/server-runtime': 2.14.0(typescript@5.6.3) + '@remix-run/web-fetch': 4.4.2 + '@web3-storage/multipart-parser': 1.0.0 + cookie-signature: 1.2.1 + source-map-support: 0.5.21 + stream-slice: 0.1.2 + undici: 6.14.1 + optionalDependencies: + typescript: 5.6.3 + + '@remix-run/node@2.14.0(typescript@5.6.3)': + dependencies: + '@remix-run/server-runtime': 2.14.0(typescript@5.6.3) '@remix-run/web-fetch': 4.4.2 '@web3-storage/multipart-parser': 1.0.0 cookie-signature: 1.2.1 @@ -8216,35 +8272,35 @@ snapshots: optionalDependencies: typescript: 5.6.3 - '@remix-run/react@2.13.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@remix-run/react@2.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@remix-run/router': 1.20.0 - '@remix-run/server-runtime': 2.13.1(typescript@5.6.3) + '@remix-run/router': 1.21.0 + '@remix-run/server-runtime': 2.14.0(typescript@5.6.3) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-router: 6.27.0(react@18.3.1) - react-router-dom: 6.27.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-router: 6.28.0(react@18.3.1) + react-router-dom: 6.28.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) turbo-stream: 2.4.0 optionalDependencies: typescript: 5.6.3 - '@remix-run/react@2.13.1(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701)(typescript@5.6.3)': + '@remix-run/react@2.14.0(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701)(typescript@5.6.3)': dependencies: - '@remix-run/router': 1.20.0 - '@remix-run/server-runtime': 2.13.1(typescript@5.6.3) + '@remix-run/router': 1.21.0 + '@remix-run/server-runtime': 2.14.0(typescript@5.6.3) react: 19.0.0-rc-100dfd7dab-20240701 react-dom: 19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701) - react-router: 6.27.0(react@19.0.0-rc-100dfd7dab-20240701) - react-router-dom: 6.27.0(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701) + react-router: 6.28.0(react@19.0.0-rc-100dfd7dab-20240701) + react-router-dom: 6.28.0(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701) turbo-stream: 2.4.0 optionalDependencies: typescript: 5.6.3 - '@remix-run/router@1.20.0': {} + '@remix-run/router@1.21.0': {} - '@remix-run/server-runtime@2.13.1(typescript@5.6.3)': + '@remix-run/server-runtime@2.14.0(typescript@5.6.3)': dependencies: - '@remix-run/router': 1.20.0 + '@remix-run/router': 1.21.0 '@types/cookie': 0.6.0 '@web3-storage/multipart-parser': 1.0.0 cookie: 0.6.0 @@ -12803,6 +12859,13 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 + react-dom@18.3.1(react@19.0.0-rc-100dfd7dab-20240701): + dependencies: + loose-envify: 1.4.0 + react: 19.0.0-rc-100dfd7dab-20240701 + scheduler: 0.23.2 + optional: true + react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701): dependencies: react: 19.0.0-rc-100dfd7dab-20240701 @@ -12814,28 +12877,28 @@ snapshots: react-refresh@0.14.0: {} - react-router-dom@6.27.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-router-dom@6.28.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@remix-run/router': 1.20.0 + '@remix-run/router': 1.21.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-router: 6.27.0(react@18.3.1) + react-router: 6.28.0(react@18.3.1) - react-router-dom@6.27.0(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701): + react-router-dom@6.28.0(react-dom@19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701): dependencies: - '@remix-run/router': 1.20.0 + '@remix-run/router': 1.21.0 react: 19.0.0-rc-100dfd7dab-20240701 react-dom: 19.0.0-rc-100dfd7dab-20240701(react@19.0.0-rc-100dfd7dab-20240701) - react-router: 6.27.0(react@19.0.0-rc-100dfd7dab-20240701) + react-router: 6.28.0(react@19.0.0-rc-100dfd7dab-20240701) - react-router@6.27.0(react@18.3.1): + react-router@6.28.0(react@18.3.1): dependencies: - '@remix-run/router': 1.20.0 + '@remix-run/router': 1.21.0 react: 18.3.1 - react-router@6.27.0(react@19.0.0-rc-100dfd7dab-20240701): + react-router@6.28.0(react@19.0.0-rc-100dfd7dab-20240701): dependencies: - '@remix-run/router': 1.20.0 + '@remix-run/router': 1.21.0 react: 19.0.0-rc-100dfd7dab-20240701 react-router@7.0.0-pre.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1): @@ -12850,6 +12913,18 @@ snapshots: optionalDependencies: react-dom: 18.3.1(react@18.3.1) + react-router@7.0.0-pre.5(react-dom@18.3.1(react@19.0.0-rc-100dfd7dab-20240701))(react@19.0.0-rc-100dfd7dab-20240701): + dependencies: + '@types/cookie': 0.6.0 + '@web3-storage/multipart-parser': 1.0.0 + cookie: 1.0.1 + react: 19.0.0-rc-100dfd7dab-20240701 + set-cookie-parser: 2.6.0 + source-map: 0.7.4 + turbo-stream: 2.4.0 + optionalDependencies: + react-dom: 18.3.1(react@19.0.0-rc-100dfd7dab-20240701) + react@18.3.1: dependencies: loose-envify: 1.4.0 diff --git a/render.yaml b/render.yaml index 894d9e39..43373167 100644 --- a/render.yaml +++ b/render.yaml @@ -45,4 +45,3 @@ services: - ./packages/**/* buildCommand: corepack enable && pnpm i && pnpm run build startCommand: cd examples/react-router && pnpm run start - From a30e9fbf7e297a7ff75fda90126633fc049c10e6 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Fri, 15 Nov 2024 19:04:53 -0500 Subject: [PATCH 02/13] feat: update package name for react router example template Signed-off-by: Logan McAnsh --- examples/react-router/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/react-router/package.json b/examples/react-router/package.json index f7a250b6..c8f04916 100644 --- a/examples/react-router/package.json +++ b/examples/react-router/package.json @@ -1,4 +1,5 @@ { + "name": "react-router-example-template", "private": true, "sideEffects": false, "type": "module", From f568518c910b299e8d4a33dbe8ab937e7d5d79b0 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Fri, 15 Nov 2024 19:28:13 -0500 Subject: [PATCH 03/13] chore: adjust more things, add tests for RR Signed-off-by: Logan McAnsh --- .../remix-fastify/__tests__/index.test.ts | 329 ++++++++++-------- .../remix-fastify/src/servers/react-router.ts | 20 +- packages/remix-fastify/src/servers/remix.ts | 16 +- packages/remix-fastify/src/shared.ts | 24 +- 4 files changed, 211 insertions(+), 178 deletions(-) diff --git a/packages/remix-fastify/__tests__/index.test.ts b/packages/remix-fastify/__tests__/index.test.ts index baf52b62..c828d687 100644 --- a/packages/remix-fastify/__tests__/index.test.ts +++ b/packages/remix-fastify/__tests__/index.test.ts @@ -3,18 +3,16 @@ import type { FastifyReply, FastifyRequest } from "fastify"; import fastify from "fastify"; import { createRequest } from "node-mocks-http"; import { - createReadableStreamFromReadable, + createReadableStreamFromReadable as remixCreateReadableStreamFromReadable, createRequestHandler as createRemixRequestHandler, } from "@remix-run/node"; -import "@remix-run/node/install"; +import { createRequestHandler as createReactRouterRequestHandler } from "react-router"; +import { createReadableStreamFromReadable as reactRouterCreateReadableStreamFromReadable } from "@react-router/node"; import type { MockedFunction } from "vitest"; import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; -import { - createRemixHeaders, - createRemixRequest, - createRequestHandler, -} from "../src/server"; +import { createRemixRequest, createRequestHandler } from "../src/servers/remix"; +import { createHeaders } from "../src/shared"; // We don't want to test that the remix server works here (that's what the // playwright tests do), we just want to test the fastify adapter @@ -27,9 +25,24 @@ vi.mock("@remix-run/node", async () => { createRequestHandler: vi.fn(), }; }); -let mockedCreateRequestHandler = createRemixRequestHandler as MockedFunction< - typeof createRemixRequestHandler ->; +// We don't want to test that the remix server works here (that's what the +// playwright tests do), we just want to test the fastify adapter +vi.mock("react-router", async () => { + let original = + // eslint-disable-next-line @typescript-eslint/consistent-type-imports + await vi.importActual("react-router"); + return { + ...original, + createRequestHandler: vi.fn(), + }; +}); + +let mockedRemixCreateRequestHandler = + createRemixRequestHandler as MockedFunction; +let mockedReactRouterCreateRequestHandler = + createReactRouterRequestHandler as MockedFunction< + typeof createReactRouterRequestHandler + >; function createApp() { let app = fastify(); @@ -47,187 +60,211 @@ function createApp() { return app; } -describe("fastify createRequestHandler", () => { - describe("basic requests", () => { - afterEach(() => { - mockedCreateRequestHandler.mockReset(); - }); - - afterAll(() => { - vi.restoreAllMocks(); - }); +function runTests( + name: string, + { + createReadableStreamFromReadable, + handler, + }: { + handler: + | typeof mockedRemixCreateRequestHandler + | typeof mockedReactRouterCreateRequestHandler; + createReadableStreamFromReadable: + | typeof remixCreateReadableStreamFromReadable + | typeof reactRouterCreateReadableStreamFromReadable; + }, +) { + describe(`[${name}] fastify createRequestHandler`, () => { + describe(`[${name}] basic requests`, () => { + afterEach(() => { + handler.mockReset(); + }); - it("handles requests", async () => { - mockedCreateRequestHandler.mockImplementation(() => async (req) => { - return new Response(`URL: ${new URL(req.url).pathname}`); + afterAll(() => { + vi.restoreAllMocks(); }); - let app = createApp(); + it(`[${name}] handles requests`, async () => { + handler.mockImplementation(() => async (req) => { + return new Response(`URL: ${new URL(req.url).pathname}`); + }); - let response = await app.inject("/foo/bar"); + let app = createApp(); - expect(response.body).toBe("URL: /foo/bar"); - expect(response.statusCode).toBe(200); - }); + let response = await app.inject("/foo/bar"); - it("handles root // URLs", async () => { - mockedCreateRequestHandler.mockImplementation(() => async (req) => { - return new Response(`URL: ${new URL(req.url).pathname}`); + expect(response.body).toBe("URL: /foo/bar"); + expect(response.statusCode).toBe(200); }); - let app = createApp(); + it(`[${name}] handles root // URLs`, async () => { + handler.mockImplementation(() => async (req) => { + return new Response(`URL: ${new URL(req.url).pathname}`); + }); - let response = await app.inject("//"); + let app = createApp(); - expect(response.statusCode).toBe(200); - expect(response.body).toBe("URL: //"); - }); + let response = await app.inject("//"); - it("handles nested // URLs", async () => { - mockedCreateRequestHandler.mockImplementation(() => async (req) => { - return new Response(`URL: ${new URL(req.url).pathname}`); + expect(response.statusCode).toBe(200); + expect(response.body).toBe("URL: //"); }); - let app = createApp(); + it(`[${name}] handles nested // URLs`, async () => { + handler.mockImplementation(() => async (req) => { + return new Response(`URL: ${new URL(req.url).pathname}`); + }); - let response = await app.inject("//foo//bar"); + let app = createApp(); - expect(response.statusCode).toBe(200); - expect(response.body).toBe("URL: //foo//bar"); - }); + let response = await app.inject("//foo//bar"); - it("handles null body", async () => { - mockedCreateRequestHandler.mockImplementation(() => async () => { - return new Response(null); + expect(response.statusCode).toBe(200); + expect(response.body).toBe("URL: //foo//bar"); }); - let app = createApp(); + it(`[${name}] handles null body`, async () => { + handler.mockImplementation(() => async () => { + return new Response(null); + }); - let response = await app.inject("/"); + let app = createApp(); - expect(response.statusCode).toBe(200); - }); + let response = await app.inject("/"); - // https://github.com/node-fetch/node-fetch/blob/4ae35388b078bddda238277142bf091898ce6fda/test/response.js#L142-L148 - it("handles body as stream", async () => { - mockedCreateRequestHandler.mockImplementation(() => async () => { - let readable = Readable.from("hello world"); - let stream = createReadableStreamFromReadable(readable); - return new Response(stream); + expect(response.statusCode).toBe(200); }); - let app = createApp(); - let response = await app.inject("/"); + // https://github.com/node-fetch/node-fetch/blob/4ae35388b078bddda238277142bf091898ce6fda/test/response.js#L142-L148 + it(`[${name}] handles body as stream`, async () => { + handler.mockImplementation(() => async () => { + let readable = Readable.from("hello world"); + let stream = createReadableStreamFromReadable(readable); + return new Response(stream); + }); - expect(response.statusCode).toBe(200); - expect(response.body).toBe("hello world"); - }); + let app = createApp(); + let response = await app.inject("/"); - it("handles status codes", async () => { - mockedCreateRequestHandler.mockImplementation(() => async () => { - return new Response(null, { status: 204 }); + expect(response.statusCode).toBe(200); + expect(response.body).toBe("hello world"); }); - let app = createApp(); - let response = await app.inject("/"); + it(`[${name}] handles status codes`, async () => { + handler.mockImplementation(() => async () => { + return new Response(null, { status: 204 }); + }); - expect(response.statusCode).toBe(204); - }); + let app = createApp(); + let response = await app.inject("/"); - it("sets headers", async () => { - mockedCreateRequestHandler.mockImplementation(() => async () => { - let headers = new Headers({ "X-Time-Of-Year": "most wonderful" }); - headers.append( - "Set-Cookie", + expect(response.statusCode).toBe(204); + }); + + it(`[${name}] sets headers`, async () => { + handler.mockImplementation(() => async () => { + let headers = new Headers({ "X-Time-Of-Year": "most wonderful" }); + headers.append( + "Set-Cookie", + "first=one; Expires=0; Path=/; HttpOnly; Secure; SameSite=Lax", + ); + headers.append( + "Set-Cookie", + "second=two; MaxAge=1209600; Path=/; HttpOnly; Secure; SameSite=Lax", + ); + headers.append( + "Set-Cookie", + "third=three; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Path=/; HttpOnly; Secure; SameSite=Lax", + ); + return new Response(null, { headers }); + }); + + let app = createApp(); + let response = await app.inject("/"); + + expect(response.headers["x-time-of-year"]).toBe("most wonderful"); + expect(response.headers["set-cookie"]).toEqual([ "first=one; Expires=0; Path=/; HttpOnly; Secure; SameSite=Lax", - ); - headers.append( - "Set-Cookie", "second=two; MaxAge=1209600; Path=/; HttpOnly; Secure; SameSite=Lax", - ); - headers.append( - "Set-Cookie", "third=three; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Path=/; HttpOnly; Secure; SameSite=Lax", - ); - return new Response(null, { headers }); + ]); }); - - let app = createApp(); - let response = await app.inject("/"); - - expect(response.headers["x-time-of-year"]).toBe("most wonderful"); - expect(response.headers["set-cookie"]).toEqual([ - "first=one; Expires=0; Path=/; HttpOnly; Secure; SameSite=Lax", - "second=two; MaxAge=1209600; Path=/; HttpOnly; Secure; SameSite=Lax", - "third=three; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Path=/; HttpOnly; Secure; SameSite=Lax", - ]); }); }); -}); -describe("fastify createRemixHeaders", () => { - describe("creates fetch headers from fastify headers", () => { - it("handles empty headers", () => { - let headers = createRemixHeaders({}); - expect(Array.from(headers.keys())).toHaveLength(0); - }); + describe(`[${name}] fastify createHeaders`, () => { + describe(`[${name}] creates fetch headers from fastify headers`, () => { + it(`[${name}] handles empty headers`, () => { + let headers = createHeaders({}); + expect(Array.from(headers.keys())).toHaveLength(0); + }); - it("handles simple headers", () => { - let headers = createRemixHeaders({ "x-foo": "bar" }); - expect(headers.get("x-foo")).toBe("bar"); - }); + it(`[${name}] handles simple headers`, () => { + let headers = createHeaders({ "x-foo": "bar" }); + expect(headers.get("x-foo")).toBe("bar"); + }); - it("handles multiple headers", () => { - let headers = createRemixHeaders({ "x-foo": "bar", "x-bar": "baz" }); - expect(headers.get("x-foo")).toBe("bar"); - }); + it(`[${name}] handles multiple headers`, () => { + let headers = createHeaders({ "x-foo": "bar", "x-bar": "baz" }); + expect(headers.get("x-foo")).toBe("bar"); + }); - it("handles headers with multiple values", () => { - let headers = createRemixHeaders({ "x-foo": "bar, baz" }); - expect(headers.get("x-foo")).toBe("bar, baz"); - }); + it(`[${name}] handles headers with multiple values`, () => { + let headers = createHeaders({ "x-foo": "bar, baz" }); + expect(headers.get("x-foo")).toBe("bar, baz"); + }); - it("handles headers with multiple values and multiple headers", () => { - let headers = createRemixHeaders({ "x-foo": "bar, baz", "x-bar": "baz" }); - expect(headers.get("x-foo")).toBe("bar, baz"); - expect(headers.get("x-bar")).toBe("baz"); - }); + it(`[${name}] handles headers with multiple values and multiple headers`, () => { + let headers = createHeaders({ "x-foo": "bar, baz", "x-bar": "baz" }); + expect(headers.get("x-foo")).toBe("bar, baz"); + expect(headers.get("x-bar")).toBe("baz"); + }); - it("handles multiple set-cookie headers", () => { - let headers = createRemixHeaders({ - "set-cookie": [ - "__session=some_value; Path=/; Secure; HttpOnly; MaxAge=7200; SameSite=Lax", - "__other=some_other_value; Path=/; Secure; HttpOnly; MaxAge=3600; SameSite=Lax", - ], + it(`[${name}] handles multiple set-cookie headers`, () => { + let headers = createHeaders({ + "set-cookie": [ + "__session=some_value; Path=/; Secure; HttpOnly; MaxAge=7200; SameSite=Lax", + "__other=some_other_value; Path=/; Secure; HttpOnly; MaxAge=3600; SameSite=Lax", + ], + }); + + expect(headers.get("set-cookie")).toBe( + "__session=some_value; Path=/; Secure; HttpOnly; MaxAge=7200; SameSite=Lax, __other=some_other_value; Path=/; Secure; HttpOnly; MaxAge=3600; SameSite=Lax", + ); }); + }); + }); - expect(headers.get("set-cookie")).toBe( - "__session=some_value; Path=/; Secure; HttpOnly; MaxAge=7200; SameSite=Lax, __other=some_other_value; Path=/; Secure; HttpOnly; MaxAge=3600; SameSite=Lax", + describe("fastify createRemixRequest", () => { + it(`[${name}] creates a request with the correct headers`, async () => { + let fastifyRequest = createRequest({ + url: "/foo/bar", + method: "GET", + protocol: "http", + hostname: "localhost:3000", + headers: { + "Cache-Control": "max-age=300, s-maxage=3600", + Host: "localhost:3000", + }, + }) as unknown as FastifyRequest; + + let fastifyReply = { raw: { on: vi.fn() } } as unknown as FastifyReply; + + let request = createRemixRequest(fastifyRequest, fastifyReply); + + expect(request.headers.get("cache-control")).toBe( + "max-age=300, s-maxage=3600", ); + expect(request.headers.get("host")).toBe("localhost:3000"); }); }); -}); +} -describe("fastify createRemixRequest", () => { - it("creates a request with the correct headers", async () => { - let fastifyRequest = createRequest({ - url: "/foo/bar", - method: "GET", - protocol: "http", - hostname: "localhost:3000", - headers: { - "Cache-Control": "max-age=300, s-maxage=3600", - Host: "localhost:3000", - }, - }) as unknown as FastifyRequest; - - let fastifyReply = { raw: { on: vi.fn() } } as unknown as FastifyReply; - - let request = createRemixRequest(fastifyRequest, fastifyReply); - - expect(request.headers.get("cache-control")).toBe( - "max-age=300, s-maxage=3600", - ); - expect(request.headers.get("host")).toBe("localhost:3000"); - }); +runTests("remix", { + handler: mockedRemixCreateRequestHandler, + createReadableStreamFromReadable: remixCreateReadableStreamFromReadable, +}); +runTests("react-router", { + handler: mockedReactRouterCreateRequestHandler, + createReadableStreamFromReadable: reactRouterCreateReadableStreamFromReadable, }); diff --git a/packages/remix-fastify/src/servers/react-router.ts b/packages/remix-fastify/src/servers/react-router.ts index c7bdf71d..46383a34 100644 --- a/packages/remix-fastify/src/servers/react-router.ts +++ b/packages/remix-fastify/src/servers/react-router.ts @@ -3,14 +3,14 @@ import type { FastifyReply, RouteGenericInterface, } from "fastify"; -import { createRequestHandler as createRemixRequestHandler } from "react-router"; import type { AppLoadContext, ServerBuild } from "react-router"; +import { createRequestHandler as createRemixRequestHandler } from "react-router"; import { createReadableStreamFromReadable } from "@react-router/node"; -import { createRequestInit, getUrl, sendResponse } from "../shared"; +import { createRequest, sendResponse } from "../shared"; import type { + GetLoadContextFunction as GenericGetLoadContextFunction, HttpServer, RequestHandler, - GetLoadContextFunction as GenericGetLoadContextFunction, } from "../shared"; export type CreateRequestHandlerFunction = typeof createRequestHandler; @@ -32,24 +32,16 @@ export function createRequestHandler({ let handleRequest = createRemixRequestHandler(build, mode); return async (request, reply) => { - let remixRequest = createRequest(request, reply); + let remixRequest = createReactRouterRequest(request, reply); let loadContext = await getLoadContext?.(request, reply); let response = await handleRequest(remixRequest, loadContext); return sendResponse(reply, response); }; } -function createRequest( +export function createReactRouterRequest( request: FastifyRequest, reply: FastifyReply, ): Request { - let url = getUrl(request); - let init = createRequestInit(request, reply); - - if (request.method !== "GET" && request.method !== "HEAD") { - init.body = createReadableStreamFromReadable(request.raw); - init.duplex = "half"; - } - - return new Request(url, init); + return createRequest(request, reply, createReadableStreamFromReadable); } diff --git a/packages/remix-fastify/src/servers/remix.ts b/packages/remix-fastify/src/servers/remix.ts index 3d0150c7..336654a1 100644 --- a/packages/remix-fastify/src/servers/remix.ts +++ b/packages/remix-fastify/src/servers/remix.ts @@ -8,7 +8,7 @@ import { createRequestHandler as createRemixRequestHandler, createReadableStreamFromReadable, } from "@remix-run/node"; -import { createRequestInit, getUrl, sendResponse } from "../shared"; +import { createRequest, sendResponse } from "../shared"; import type { GetLoadContextFunction as GenericGetLoadContextFunction, HttpServer, @@ -34,24 +34,16 @@ export function createRequestHandler({ let handleRequest = createRemixRequestHandler(build, mode); return async (request, reply) => { - let remixRequest = createRequest(request, reply); + let remixRequest = createRemixRequest(request, reply); let loadContext = await getLoadContext?.(request, reply); let response = await handleRequest(remixRequest, loadContext); return sendResponse(reply, response); }; } -function createRequest( +export function createRemixRequest( request: FastifyRequest, reply: FastifyReply, ): Request { - let url = getUrl(request); - let init = createRequestInit(request, reply); - - if (request.method !== "GET" && request.method !== "HEAD") { - init.body = createReadableStreamFromReadable(request.raw); - init.duplex = "half"; - } - - return new Request(url, init); + return createRequest(request, reply, createReadableStreamFromReadable); } diff --git a/packages/remix-fastify/src/shared.ts b/packages/remix-fastify/src/shared.ts index ce2eb600..6a2dec50 100644 --- a/packages/remix-fastify/src/shared.ts +++ b/packages/remix-fastify/src/shared.ts @@ -9,6 +9,8 @@ import type { RawRequestDefaultExpression, RouteGenericInterface, } from "fastify"; +import type { createReadableStreamFromReadable as RRCreateReadableStreamFromReadable } from "@react-router/node"; +import type { createReadableStreamFromReadable as RemixCreateReadableStreamFromReadable } from "@remix-run/node"; export type HttpServer = | http.Server @@ -39,7 +41,7 @@ export type GetLoadContextFunction< reply: FastifyReply, ) => Promise | AppLoadContext; -export function createRemixHeaders( +export function createHeaders( requestHeaders: FastifyRequest["headers"], ): Headers { let headers = new Headers(); @@ -63,20 +65,25 @@ export function getUrl( request: FastifyRequest, ): string { let origin = `${request.protocol}://${request.host}`; - // Use `request.originalUrl` so Remix is aware of the full path + // Use `request.originalUrl` so Remix and React Router are aware of the full path let url = `${origin}${request.originalUrl}`; return url; } -export function createRequestInit( +export function createRequest( request: FastifyRequest, reply: FastifyReply, -): RequestInit { + createReadableStreamFromReadable: + | typeof RemixCreateReadableStreamFromReadable + | typeof RRCreateReadableStreamFromReadable, +): Request { + let url = getUrl(request); + let controller: AbortController | null = new AbortController(); let init: RequestInit = { method: request.method, - headers: createRemixHeaders(request.headers), + headers: createHeaders(request.headers), signal: controller.signal, }; @@ -87,7 +94,12 @@ export function createRequestInit( reply.raw.on("finish", () => (controller = null)); reply.raw.on("close", () => controller?.abort()); - return init; + if (request.method !== "GET" && request.method !== "HEAD") { + init.body = createReadableStreamFromReadable(request.raw); + init.duplex = "half"; + } + + return new Request(url, init); } export async function sendResponse( From f0de954cbf9d135aa66839864e85fa18ed5fa2f7 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Fri, 15 Nov 2024 20:18:17 -0500 Subject: [PATCH 04/13] Update tsup.config.ts --- packages/remix-fastify/tsup.config.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/remix-fastify/tsup.config.ts b/packages/remix-fastify/tsup.config.ts index ab514f00..86691a61 100644 --- a/packages/remix-fastify/tsup.config.ts +++ b/packages/remix-fastify/tsup.config.ts @@ -6,11 +6,11 @@ import pkg from "./package.json"; export default defineConfig(() => { return { - entry: { - index: "./src/index.ts", - remix: "./src/remix.ts", - "react-router": "./src/react-router.ts", - }, + entry: [ + "./src/index.ts", + "./src/remix.ts", + "./src/react-router.ts", + ], sourcemap: true, tsconfig: "./tsconfig.json", dts: true, From 8b6d6c0b7a4c64d7e20937c431f8b538237777e1 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Fri, 15 Nov 2024 20:19:40 -0500 Subject: [PATCH 05/13] Update react-router.ts --- packages/remix-fastify/src/servers/react-router.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/remix-fastify/src/servers/react-router.ts b/packages/remix-fastify/src/servers/react-router.ts index 46383a34..3fc35e2d 100644 --- a/packages/remix-fastify/src/servers/react-router.ts +++ b/packages/remix-fastify/src/servers/react-router.ts @@ -4,7 +4,7 @@ import type { RouteGenericInterface, } from "fastify"; import type { AppLoadContext, ServerBuild } from "react-router"; -import { createRequestHandler as createRemixRequestHandler } from "react-router"; +import { createRequestHandler as createReactRouterRequestHandler } from "react-router"; import { createReadableStreamFromReadable } from "@react-router/node"; import { createRequest, sendResponse } from "../shared"; import type { @@ -29,7 +29,7 @@ export function createRequestHandler({ getLoadContext?: GetLoadContextFunction; mode?: string; }): RequestHandler { - let handleRequest = createRemixRequestHandler(build, mode); + let handleRequest = createReactRouterRequestHandler(build, mode); return async (request, reply) => { let remixRequest = createReactRouterRequest(request, reply); From f369dc4f2b59f0248401049361f5900c5b2148c0 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Sat, 16 Nov 2024 22:53:02 -0500 Subject: [PATCH 06/13] chore: update pnpm Signed-off-by: Logan McAnsh --- .gitignore | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ee0c01a1..96977535 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ yalc.lock # added during build /packages/*/LICENSE .tsup +.idea diff --git a/package.json b/package.json index b950b84a..1a27d00e 100644 --- a/package.json +++ b/package.json @@ -44,5 +44,5 @@ "typescript": "^5.6.3", "vitest": "^2.1.3" }, - "packageManager": "pnpm@9.11.0+sha512.0a203ffaed5a3f63242cd064c8fb5892366c103e328079318f78062f24ea8c9d50bc6a47aa3567cabefd824d170e78fa2745ed1f16b132e16436146b7688f19b" + "packageManager": "pnpm@9.13.2+sha512.88c9c3864450350e65a33587ab801acf946d7c814ed1134da4a924f6df5a2120fd36b46aab68f7cd1d413149112d53c7db3a4136624cfd00ff1846a0c6cef48a" } From 48b268d2a1935d8b1c13c37131a9abb741ff0300 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Sat, 16 Nov 2024 23:00:39 -0500 Subject: [PATCH 07/13] chore: use @total-typescript/tsconfig/bundler/no-dom/library for tsconfig Signed-off-by: Logan McAnsh --- package.json | 1 + packages/remix-fastify/tsconfig.json | 19 +++---------- pnpm-lock.yaml | 40 +++++++++++++++++----------- 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 1a27d00e..3047e292 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@manypkg/get-packages": "^2.2.2", "@npmcli/package-json": "^6.0.1", "@remix-run/eslint-config": "2.13.1", + "@total-typescript/tsconfig": "^1.0.4", "@types/npmcli__package-json": "^4.0.4", "chalk": "^5.3.0", "eslint": "^9.13.0", diff --git a/packages/remix-fastify/tsconfig.json b/packages/remix-fastify/tsconfig.json index e12e8bab..acd66781 100644 --- a/packages/remix-fastify/tsconfig.json +++ b/packages/remix-fastify/tsconfig.json @@ -1,23 +1,10 @@ { "exclude": ["./dist", "./__tests__", "./node_modules"], "include": ["./src"], + "extends": "@total-typescript/tsconfig/bundler/no-dom/library", "compilerOptions": { - "lib": ["DOM", "DOM.Iterable", "ES2022"], - "target": "ES2022", - "module": "ES2022", - "verbatimModuleSyntax": true, - "noUncheckedIndexedAccess": true, - - "moduleResolution": "Bundler", - "moduleDetection": "force", - "strict": true, - "outDir": "./dist", - "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "esModuleInterop": true, - "isolatedModules": true, - "rootDir": ".", - "declaration": true, - "emitDeclarationOnly": true + "outDir": "./dist", + "rootDir": "." } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 353a4062..c19a0e7e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,6 +25,9 @@ importers: '@remix-run/eslint-config': specifier: latest version: 2.14.0(eslint@9.13.0(jiti@2.3.3))(react@18.3.1)(typescript@5.6.3) + '@total-typescript/tsconfig': + specifier: ^1.0.4 + version: 1.0.4 '@types/npmcli__package-json': specifier: ^4.0.4 version: 4.0.4 @@ -2011,6 +2014,9 @@ packages: resolution: {integrity: sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==} engines: {node: '>=12'} + '@total-typescript/tsconfig@1.0.4': + resolution: {integrity: sha512-fO4ctMPGz1kOFOQ4RCPBRBfMy3gDn+pegUfrGyUFRMv/Rd0ZM3/SHH3hFCYG4u6bPLG8OlmOGcBLDexvyr3A5w==} + '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -8204,7 +8210,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.6.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jest: 26.9.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3) eslint-plugin-jest-dom: 4.0.3(eslint@8.57.0) @@ -8461,6 +8467,8 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 + '@total-typescript/tsconfig@1.0.4': {} + '@tsconfig/node10@1.0.11': optional: true @@ -10115,12 +10123,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 @@ -10137,7 +10145,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 @@ -10155,7 +10163,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 9.13.0(jiti@2.3.3) - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.31.0)(eslint@9.13.0(jiti@2.3.3)))(eslint@9.13.0(jiti@2.3.3)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0(jiti@2.3.3)) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -10168,7 +10176,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.31.0)(eslint@9.13.0(jiti@2.3.3)))(eslint@9.13.0(jiti@2.3.3)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0(jiti@2.3.3)): dependencies: debug: 3.2.7 optionalDependencies: @@ -10179,7 +10187,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.31.0)(eslint@9.13.0(jiti@2.3.3)))(eslint@9.13.0(jiti@2.3.3)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0(jiti@2.3.3)): dependencies: debug: 3.2.7 optionalDependencies: @@ -10190,29 +10198,29 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.6.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.6.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -10223,7 +10231,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -10256,7 +10264,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -10283,7 +10291,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -10311,7 +10319,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.13.0(jiti@2.3.3) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.31.0)(eslint@9.13.0(jiti@2.3.3)))(eslint@9.13.0(jiti@2.3.3)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0(jiti@2.3.3)) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 From c0e71b6213f7f2f64793c8250f32c35cb6b78ae4 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Sat, 16 Nov 2024 23:07:43 -0500 Subject: [PATCH 08/13] chore: use @total-typescript/tsconfig/bundler/dom/app for examples Signed-off-by: Logan McAnsh --- examples/basic/package.json | 1 + examples/basic/tsconfig.json | 12 ++---------- examples/playground/package.json | 1 + examples/playground/tsconfig.json | 15 +++------------ examples/react-router/package.json | 1 + examples/react-router/tsconfig.json | 11 +---------- examples/vite/package.json | 1 + examples/vite/tsconfig.json | 14 +------------- pnpm-lock.yaml | 28 ++++++++++++++++++++-------- 9 files changed, 31 insertions(+), 53 deletions(-) diff --git a/examples/basic/package.json b/examples/basic/package.json index 6e0710f4..572b0d95 100644 --- a/examples/basic/package.json +++ b/examples/basic/package.json @@ -29,6 +29,7 @@ "devDependencies": { "@remix-run/dev": "*", "@remix-run/eslint-config": "*", + "@total-typescript/tsconfig": "^1.0.4", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.1", "chokidar": "^4.0.1", diff --git a/examples/basic/tsconfig.json b/examples/basic/tsconfig.json index 28cce918..1102cb76 100644 --- a/examples/basic/tsconfig.json +++ b/examples/basic/tsconfig.json @@ -1,22 +1,14 @@ { "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], + "extends": "@total-typescript/tsconfig/bundler/dom/app", "compilerOptions": { - "lib": ["DOM", "DOM.Iterable", "ES2022"], - "isolatedModules": true, - "esModuleInterop": true, + "types": ["@react-router/node", "vite/client"], "jsx": "react-jsx", - "moduleResolution": "Bundler", - "resolveJsonModule": true, - "target": "ES2022", - "strict": true, - "allowJs": true, "forceConsistentCasingInFileNames": true, "baseUrl": ".", "paths": { "~/*": ["./app/*"] }, - - // Remix takes care of building everything in `remix build`. "noEmit": true } } diff --git a/examples/playground/package.json b/examples/playground/package.json index 010b0556..ba21265c 100644 --- a/examples/playground/package.json +++ b/examples/playground/package.json @@ -32,6 +32,7 @@ "@remix-run/dev": "*", "@remix-run/eslint-config": "*", "@tailwindcss/vite": "4.0.0-alpha.28", + "@total-typescript/tsconfig": "^1.0.4", "@types/react": "npm:types-react@19.0.0-rc.1", "@types/react-dom": "npm:types-react-dom@19.0.0-rc.1", "chokidar": "^4.0.1", diff --git a/examples/playground/tsconfig.json b/examples/playground/tsconfig.json index 5a115b9c..fbb89af5 100644 --- a/examples/playground/tsconfig.json +++ b/examples/playground/tsconfig.json @@ -1,31 +1,22 @@ { + "extends": "@total-typescript/tsconfig/bundler/dom/app", "include": [ "**/*.ts", "**/*.tsx", "**/.server/**/*.ts", "**/.server/**/*.tsx", "**/.client/**/*.ts", - "**/.client/**/*.tsx" + "**/.client/**/*.tsx", + ".react-router/types/**/*" ], "compilerOptions": { - "lib": ["DOM", "DOM.Iterable", "ES2022"], "types": ["@remix-run/node", "vite/client"], - "isolatedModules": true, - "esModuleInterop": true, "jsx": "react-jsx", - "moduleResolution": "Bundler", - "resolveJsonModule": true, - "target": "ES2022", - "skipLibCheck": true, - "strict": true, - "allowJs": true, "forceConsistentCasingInFileNames": true, "baseUrl": ".", "paths": { "~/*": ["./app/*"] }, - - // Remix takes care of building everything in `remix build`. "noEmit": true } } diff --git a/examples/react-router/package.json b/examples/react-router/package.json index c8f04916..afcede09 100644 --- a/examples/react-router/package.json +++ b/examples/react-router/package.json @@ -25,6 +25,7 @@ }, "devDependencies": { "@react-router/dev": "7.0.0-pre.4", + "@total-typescript/tsconfig": "^1.0.4", "@types/react": "^18.3.9", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.20", diff --git a/examples/react-router/tsconfig.json b/examples/react-router/tsconfig.json index 29b23163..51f4efc8 100644 --- a/examples/react-router/tsconfig.json +++ b/examples/react-router/tsconfig.json @@ -1,4 +1,5 @@ { + "extends": "@total-typescript/tsconfig/bundler/dom/app", "include": [ "**/*.ts", "**/*.tsx", @@ -9,18 +10,8 @@ ".react-router/types/**/*" ], "compilerOptions": { - "lib": ["DOM", "DOM.Iterable", "ES2022"], "types": ["@react-router/node", "vite/client"], - "isolatedModules": true, - "esModuleInterop": true, "jsx": "react-jsx", - "module": "ESNext", - "moduleResolution": "Bundler", - "resolveJsonModule": true, - "target": "ES2022", - "strict": true, - "allowJs": true, - "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "baseUrl": ".", "paths": { diff --git a/examples/vite/package.json b/examples/vite/package.json index 76ae6ea7..0f676a5f 100644 --- a/examples/vite/package.json +++ b/examples/vite/package.json @@ -30,6 +30,7 @@ "devDependencies": { "@remix-run/dev": "*", "@remix-run/eslint-config": "*", + "@total-typescript/tsconfig": "^1.0.4", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.1", "@types/source-map-support": "^0.5.10", diff --git a/examples/vite/tsconfig.json b/examples/vite/tsconfig.json index c8be0c29..820b8586 100644 --- a/examples/vite/tsconfig.json +++ b/examples/vite/tsconfig.json @@ -1,4 +1,5 @@ { + "extends": "@total-typescript/tsconfig/bundler/dom/app", "include": [ "**/*.ts", "**/*.tsx", @@ -8,26 +9,13 @@ "**/.client/**/*.tsx" ], "compilerOptions": { - "lib": ["DOM", "DOM.Iterable", "ES2022"], "types": ["@remix-run/node", "vite/client"], - "isolatedModules": true, - "esModuleInterop": true, - "module": "ESNext", "jsx": "react-jsx", - "moduleResolution": "Bundler", - "moduleDetection": "force", - "resolveJsonModule": true, - "target": "ES2022", - "skipLibCheck": true, - "strict": true, - "allowJs": true, "forceConsistentCasingInFileNames": true, "baseUrl": ".", "paths": { "~/*": ["./app/*"] }, - - // Remix takes care of building everything in `remix build`. "noEmit": true } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c19a0e7e..c8aed8e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -131,6 +131,9 @@ importers: '@remix-run/eslint-config': specifier: '*' version: 2.9.0(eslint@8.57.0)(react@18.3.1)(typescript@5.6.3) + '@total-typescript/tsconfig': + specifier: ^1.0.4 + version: 1.0.4 '@types/react': specifier: ^18.3.11 version: 18.3.11 @@ -198,6 +201,9 @@ importers: '@tailwindcss/vite': specifier: 4.0.0-alpha.28 version: 4.0.0-alpha.28(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0)) + '@total-typescript/tsconfig': + specifier: ^1.0.4 + version: 1.0.4 '@types/react': specifier: npm:types-react@19.0.0-rc.1 version: types-react@19.0.0-rc.1 @@ -280,6 +286,9 @@ importers: '@react-router/dev': specifier: 7.0.0-pre.4 version: 7.0.0-pre.4(@react-router/serve@7.0.0-pre.4(react-router@7.0.0-pre.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.3))(@types/node@22.7.7)(lightningcss@1.26.0)(react-router@7.0.0-pre.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.3)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.26.0)) + '@total-typescript/tsconfig': + specifier: ^1.0.4 + version: 1.0.4 '@types/react': specifier: ^18.3.9 version: 18.3.11 @@ -359,6 +368,9 @@ importers: '@remix-run/eslint-config': specifier: '*' version: 2.9.0(eslint@8.57.0)(react@18.3.1)(typescript@5.6.3) + '@total-typescript/tsconfig': + specifier: ^1.0.4 + version: 1.0.4 '@types/react': specifier: ^18.3.11 version: 18.3.11 @@ -8210,7 +8222,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.6.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jest: 26.9.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3) eslint-plugin-jest-dom: 4.0.3(eslint@8.57.0) @@ -10123,12 +10135,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 @@ -10198,25 +10210,25 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.6.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.6.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -10264,7 +10276,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 From e03f71746b32cf2e8bdbef3af1f0d003dc60de12 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Sat, 16 Nov 2024 23:11:06 -0500 Subject: [PATCH 09/13] chore: remove console logs Signed-off-by: Logan McAnsh --- packages/remix-fastify/src/plugins/index.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/remix-fastify/src/plugins/index.ts b/packages/remix-fastify/src/plugins/index.ts index ea0b80b0..d2fdff16 100644 --- a/packages/remix-fastify/src/plugins/index.ts +++ b/packages/remix-fastify/src/plugins/index.ts @@ -100,11 +100,7 @@ export function createPlugin( | RemixCreateRequestHandlerFunction | RRCreateRequestHandlerFunction, ) { - console.log(`inside createPlugin`); - return async () => { - console.log(`inside createPlugin async`); - let cwd = process.env.REMIX_ROOT ?? process.cwd(); let vite: ViteDevServer | undefined; @@ -157,7 +153,6 @@ export function createPlugin( serveDotFiles: true, lastModified: true, setHeaders(res, filepath) { - console.log({ filepath }); let isAsset = filepath.startsWith(ASSET_DIR); res.setHeader( "cache-control", From 3a3a28b8d36e3e52ff92df6b2f5b17263c99b441 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Sun, 17 Nov 2024 20:25:49 -0500 Subject: [PATCH 10/13] chore: rename some exports and fix react router tests Signed-off-by: Logan McAnsh --- .../{index.test.ts => server.test.ts} | 111 +++++++++++------- packages/remix-fastify/src/react-router.ts | 5 +- packages/remix-fastify/src/remix.ts | 5 +- .../remix-fastify/src/servers/react-router.ts | 6 +- packages/remix-fastify/src/servers/remix.ts | 8 +- packages/remix-fastify/tsup.config.ts | 7 +- 6 files changed, 82 insertions(+), 60 deletions(-) rename packages/remix-fastify/__tests__/{index.test.ts => server.test.ts} (74%) diff --git a/packages/remix-fastify/__tests__/index.test.ts b/packages/remix-fastify/__tests__/server.test.ts similarity index 74% rename from packages/remix-fastify/__tests__/index.test.ts rename to packages/remix-fastify/__tests__/server.test.ts index c828d687..7de7c9e7 100644 --- a/packages/remix-fastify/__tests__/index.test.ts +++ b/packages/remix-fastify/__tests__/server.test.ts @@ -1,17 +1,24 @@ import { Readable } from "stream"; import type { FastifyReply, FastifyRequest } from "fastify"; import fastify from "fastify"; -import { createRequest } from "node-mocks-http"; +import { createRequest as createMockRequest } from "node-mocks-http"; import { createReadableStreamFromReadable as remixCreateReadableStreamFromReadable, - createRequestHandler as createRemixRequestHandler, + createRequestHandler as createRemixRequestHandlerImpl, } from "@remix-run/node"; -import { createRequestHandler as createReactRouterRequestHandler } from "react-router"; +import { createRequestHandler as createReactRouterRequestHandlerImpl } from "react-router"; import { createReadableStreamFromReadable as reactRouterCreateReadableStreamFromReadable } from "@react-router/node"; import type { MockedFunction } from "vitest"; import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; -import { createRemixRequest, createRequestHandler } from "../src/servers/remix"; +import { + createRemixRequest, + createRemixRequestHandler, +} from "../src/servers/remix"; +import { + createReactRouterRequest, + createReactRouterRequestHandler, +} from "../src/servers/react-router"; import { createHeaders } from "../src/shared"; // We don't want to test that the remix server works here (that's what the @@ -27,10 +34,8 @@ vi.mock("@remix-run/node", async () => { }); // We don't want to test that the remix server works here (that's what the // playwright tests do), we just want to test the fastify adapter -vi.mock("react-router", async () => { - let original = - // eslint-disable-next-line @typescript-eslint/consistent-type-imports - await vi.importActual("react-router"); +vi.mock("react-router", () => { + let original = vi.importActual("react-router"); return { ...original, createRequestHandler: vi.fn(), @@ -38,46 +43,58 @@ vi.mock("react-router", async () => { }); let mockedRemixCreateRequestHandler = - createRemixRequestHandler as MockedFunction; + createRemixRequestHandlerImpl as MockedFunction< + typeof createRemixRequestHandlerImpl + >; let mockedReactRouterCreateRequestHandler = - createReactRouterRequestHandler as MockedFunction< - typeof createReactRouterRequestHandler + createReactRouterRequestHandlerImpl as MockedFunction< + typeof createReactRouterRequestHandlerImpl >; -function createApp() { - let app = fastify(); - - app.all( - "*", - 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, - }), - ); +type MockedCreateRequestHandler = + | typeof mockedRemixCreateRequestHandler + | typeof mockedReactRouterCreateRequestHandler; - return app; -} +type CreateReadableStreamFromReadable = + | typeof remixCreateReadableStreamFromReadable + | typeof reactRouterCreateReadableStreamFromReadable; function runTests( name: string, { + createRequest, + createRequestHandler, createReadableStreamFromReadable, - handler, + mockedHandler, }: { - handler: - | typeof mockedRemixCreateRequestHandler - | typeof mockedReactRouterCreateRequestHandler; - createReadableStreamFromReadable: - | typeof remixCreateReadableStreamFromReadable - | typeof reactRouterCreateReadableStreamFromReadable; + createRequest: typeof createRemixRequest | typeof createReactRouterRequest; + createRequestHandler: + | typeof createRemixRequestHandler + | typeof createReactRouterRequestHandler; + mockedHandler: MockedCreateRequestHandler; + createReadableStreamFromReadable: CreateReadableStreamFromReadable; }, ) { + function createApp() { + let app = fastify(); + + app.all( + "*", + 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, + }), + ); + + return app; + } + describe(`[${name}] fastify createRequestHandler`, () => { describe(`[${name}] basic requests`, () => { afterEach(() => { - handler.mockReset(); + mockedHandler.mockReset(); }); afterAll(() => { @@ -85,7 +102,7 @@ function runTests( }); it(`[${name}] handles requests`, async () => { - handler.mockImplementation(() => async (req) => { + mockedHandler.mockImplementation(() => async (req) => { return new Response(`URL: ${new URL(req.url).pathname}`); }); @@ -98,7 +115,7 @@ function runTests( }); it(`[${name}] handles root // URLs`, async () => { - handler.mockImplementation(() => async (req) => { + mockedHandler.mockImplementation(() => async (req) => { return new Response(`URL: ${new URL(req.url).pathname}`); }); @@ -111,7 +128,7 @@ function runTests( }); it(`[${name}] handles nested // URLs`, async () => { - handler.mockImplementation(() => async (req) => { + mockedHandler.mockImplementation(() => async (req) => { return new Response(`URL: ${new URL(req.url).pathname}`); }); @@ -124,7 +141,7 @@ function runTests( }); it(`[${name}] handles null body`, async () => { - handler.mockImplementation(() => async () => { + mockedHandler.mockImplementation(() => async () => { return new Response(null); }); @@ -137,7 +154,7 @@ function runTests( // https://github.com/node-fetch/node-fetch/blob/4ae35388b078bddda238277142bf091898ce6fda/test/response.js#L142-L148 it(`[${name}] handles body as stream`, async () => { - handler.mockImplementation(() => async () => { + mockedHandler.mockImplementation(() => async () => { let readable = Readable.from("hello world"); let stream = createReadableStreamFromReadable(readable); return new Response(stream); @@ -151,7 +168,7 @@ function runTests( }); it(`[${name}] handles status codes`, async () => { - handler.mockImplementation(() => async () => { + mockedHandler.mockImplementation(() => async () => { return new Response(null, { status: 204 }); }); @@ -162,7 +179,7 @@ function runTests( }); it(`[${name}] sets headers`, async () => { - handler.mockImplementation(() => async () => { + mockedHandler.mockImplementation(() => async () => { let headers = new Headers({ "X-Time-Of-Year": "most wonderful" }); headers.append( "Set-Cookie", @@ -235,9 +252,9 @@ function runTests( }); }); - describe("fastify createRemixRequest", () => { + describe(`[${name}] fastify createRequest`, () => { it(`[${name}] creates a request with the correct headers`, async () => { - let fastifyRequest = createRequest({ + let fastifyRequest = createMockRequest({ url: "/foo/bar", method: "GET", protocol: "http", @@ -250,7 +267,7 @@ function runTests( let fastifyReply = { raw: { on: vi.fn() } } as unknown as FastifyReply; - let request = createRemixRequest(fastifyRequest, fastifyReply); + let request = createRequest(fastifyRequest, fastifyReply); expect(request.headers.get("cache-control")).toBe( "max-age=300, s-maxage=3600", @@ -261,10 +278,14 @@ function runTests( } runTests("remix", { - handler: mockedRemixCreateRequestHandler, + createRequest: createRemixRequest, + createRequestHandler: createRemixRequestHandler, + mockedHandler: mockedRemixCreateRequestHandler, createReadableStreamFromReadable: remixCreateReadableStreamFromReadable, }); runTests("react-router", { - handler: mockedReactRouterCreateRequestHandler, + createRequest: createReactRouterRequest, + createRequestHandler: createReactRouterRequestHandler, + mockedHandler: mockedReactRouterCreateRequestHandler, createReadableStreamFromReadable: reactRouterCreateReadableStreamFromReadable, }); diff --git a/packages/remix-fastify/src/react-router.ts b/packages/remix-fastify/src/react-router.ts index 8c396db9..3b804cfc 100644 --- a/packages/remix-fastify/src/react-router.ts +++ b/packages/remix-fastify/src/react-router.ts @@ -4,7 +4,10 @@ import type { GetLoadContextFunction as SharedGetLoadContextFunction, } from "./shared"; export type { RequestHandler } from "./shared"; -export { createRequestHandler } from "./servers/react-router"; +export { createReactRouterRequestHandler } from "./servers/react-router"; + +/** @deprecated this function has been renamed to createReactRouterRequestHandler */ +export { createReactRouterRequestHandler as createRequestHandler } from "./servers/react-router"; export { reactRouterFastify } from "./plugins/react-router"; export type { ReactRouterFastifyOptions } from "./plugins/react-router"; diff --git a/packages/remix-fastify/src/remix.ts b/packages/remix-fastify/src/remix.ts index 05f3f039..e357c8b1 100644 --- a/packages/remix-fastify/src/remix.ts +++ b/packages/remix-fastify/src/remix.ts @@ -4,7 +4,10 @@ import type { GetLoadContextFunction as SharedGetLoadContextFunction, } from "./shared"; export type { RequestHandler } from "./shared"; -export { createRequestHandler } from "./servers/remix"; +export { createRemixRequestHandler } from "./servers/remix"; + +/** @deprecated this function has been renamed to createRemixRequestHandler */ +export { createRemixRequestHandler as createRequestHandler } from "./servers/remix"; export { remixFastify } from "./plugins/remix"; export type { RemixFastifyOptions } from "./plugins/remix"; diff --git a/packages/remix-fastify/src/servers/react-router.ts b/packages/remix-fastify/src/servers/react-router.ts index 3fc35e2d..49708f6f 100644 --- a/packages/remix-fastify/src/servers/react-router.ts +++ b/packages/remix-fastify/src/servers/react-router.ts @@ -4,7 +4,7 @@ import type { RouteGenericInterface, } from "fastify"; import type { AppLoadContext, ServerBuild } from "react-router"; -import { createRequestHandler as createReactRouterRequestHandler } from "react-router"; +import { createRequestHandler } from "react-router"; import { createReadableStreamFromReadable } from "@react-router/node"; import { createRequest, sendResponse } from "../shared"; import type { @@ -20,7 +20,7 @@ export type GetLoadContextFunction = /** * Returns a request handler for Fastify that serves the response using Remix. */ -export function createRequestHandler({ +export function createReactRouterRequestHandler({ build, getLoadContext, mode = process.env.NODE_ENV, @@ -29,7 +29,7 @@ export function createRequestHandler({ getLoadContext?: GetLoadContextFunction; mode?: string; }): RequestHandler { - let handleRequest = createReactRouterRequestHandler(build, mode); + let handleRequest = createRequestHandler(build, mode); return async (request, reply) => { let remixRequest = createReactRouterRequest(request, reply); diff --git a/packages/remix-fastify/src/servers/remix.ts b/packages/remix-fastify/src/servers/remix.ts index 336654a1..20bf01ba 100644 --- a/packages/remix-fastify/src/servers/remix.ts +++ b/packages/remix-fastify/src/servers/remix.ts @@ -5,7 +5,7 @@ import type { } from "fastify"; import type { AppLoadContext, ServerBuild } from "@remix-run/node"; import { - createRequestHandler as createRemixRequestHandler, + createRequestHandler, createReadableStreamFromReadable, } from "@remix-run/node"; import { createRequest, sendResponse } from "../shared"; @@ -15,14 +15,14 @@ import type { RequestHandler, } from "../shared"; -export type CreateRequestHandlerFunction = typeof createRequestHandler; +export type CreateRequestHandlerFunction = typeof createRemixRequestHandler; export type GetLoadContextFunction = GenericGetLoadContextFunction; /** * Returns a request handler for Fastify that serves the response using Remix. */ -export function createRequestHandler({ +export function createRemixRequestHandler({ build, getLoadContext, mode = process.env.NODE_ENV, @@ -31,7 +31,7 @@ export function createRequestHandler({ getLoadContext?: GetLoadContextFunction; mode?: string; }): RequestHandler { - let handleRequest = createRemixRequestHandler(build, mode); + let handleRequest = createRequestHandler(build, mode); return async (request, reply) => { let remixRequest = createRemixRequest(request, reply); diff --git a/packages/remix-fastify/tsup.config.ts b/packages/remix-fastify/tsup.config.ts index 86691a61..559b6842 100644 --- a/packages/remix-fastify/tsup.config.ts +++ b/packages/remix-fastify/tsup.config.ts @@ -1,16 +1,11 @@ import Fsp from "node:fs/promises"; -import Path from "node:path"; import { defineConfig } from "tsup"; import pkg from "./package.json"; export default defineConfig(() => { return { - entry: [ - "./src/index.ts", - "./src/remix.ts", - "./src/react-router.ts", - ], + entry: ["./src/index.ts", "./src/remix.ts", "./src/react-router.ts"], sourcemap: true, tsconfig: "./tsconfig.json", dts: true, From 0410d5caa67806a4d2445965db48b4f228ebc765 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Sun, 17 Nov 2024 20:38:36 -0500 Subject: [PATCH 11/13] chore: update tsconfig and refactor remix handlers for improved compatibility Signed-off-by: Logan McAnsh --- examples/basic/tsconfig.json | 2 +- examples/playground/app/root.tsx | 9 +- .../playground/app/routes/_layout._index.tsx | 20 +- .../playground/app/routes/_layout.fetcher.tsx | 11 +- examples/playground/package.json | 22 +- examples/playground/vite.config.ts | 21 +- ....timestamp-1731715104505-f49232386f5ef.mjs | 12 - packages/remix-fastify/src/plugins/index.ts | 11 +- .../remix-fastify/src/plugins/react-router.ts | 10 +- packages/remix-fastify/src/plugins/remix.ts | 10 +- .../remix-fastify/src/servers/react-router.ts | 3 +- pnpm-lock.yaml | 845 ++++++++++++++---- 12 files changed, 741 insertions(+), 235 deletions(-) delete mode 100644 examples/playground/vite.config.ts.timestamp-1731715104505-f49232386f5ef.mjs diff --git a/examples/basic/tsconfig.json b/examples/basic/tsconfig.json index 1102cb76..da074f91 100644 --- a/examples/basic/tsconfig.json +++ b/examples/basic/tsconfig.json @@ -2,7 +2,7 @@ "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], "extends": "@total-typescript/tsconfig/bundler/dom/app", "compilerOptions": { - "types": ["@react-router/node", "vite/client"], + "types": ["@remix-run/node"], "jsx": "react-jsx", "forceConsistentCasingInFileNames": true, "baseUrl": ".", diff --git a/examples/playground/app/root.tsx b/examples/playground/app/root.tsx index d06fd0d2..bd234991 100644 --- a/examples/playground/app/root.tsx +++ b/examples/playground/app/root.tsx @@ -1,4 +1,4 @@ -import { json } from "@remix-run/node"; +import { data } from "@remix-run/node"; import { Links, Meta, @@ -10,11 +10,12 @@ import { import "./styles/global.css"; export function loader() { - return json({ message: "Hello from the root loader" }); + return data({ message: "Hello from the root loader" }); } export default function App() { - let data = useLoaderData(); + let loaderData = useLoaderData(); + return ( @@ -28,7 +29,7 @@ export default function App() {
- {data.message} + {loaderData.message}
diff --git a/examples/playground/app/routes/_layout._index.tsx b/examples/playground/app/routes/_layout._index.tsx index 7bb2ad30..3cbaa5ad 100644 --- a/examples/playground/app/routes/_layout._index.tsx +++ b/examples/playground/app/routes/_layout._index.tsx @@ -1,12 +1,12 @@ import * as React from "react"; -import type { DataFunctionArgs } from "@remix-run/node"; -import { defer, redirect } from "@remix-run/node"; +import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node"; +import { redirect } from "@remix-run/node"; import { Await, Form, useAsyncValue, useLoaderData } from "@remix-run/react"; import { sessionStorage } from "~/session.server"; import { sleep } from "~/sleep"; -export async function loader({ request, context }: DataFunctionArgs) { +export async function loader({ request, context }: LoaderFunctionArgs) { let cookie = request.headers.get("Cookie"); let session = await sessionStorage.getSession(cookie); @@ -16,13 +16,13 @@ export async function loader({ request, context }: DataFunctionArgs) { throw new Error("loadContextName must be a string"); } - return defer({ + return { name: sleep(1_000, session.get("name") || "Anonymous"), loadContextName, - }); + }; } -export async function action({ request }: DataFunctionArgs) { +export async function action({ request }: ActionFunctionArgs) { let cookie = request.headers.get("Cookie"); let session = await sessionStorage.getSession(cookie); let formData = await request.formData(); @@ -55,24 +55,24 @@ export async function action({ request }: DataFunctionArgs) { } export default function Index() { - let data = useLoaderData(); + let loaderData = useLoaderData(); const [echo, setEcho] = React.useState(null); return ( <> loading...}> - failed...}> + failed...}> {(resolvedName) =>

Hello {resolvedName}

}
-

Context: {data.loadContextName}

+

Context: {loaderData.loadContextName}