nahuel.luca()

How use Remix + Hono

Hono - is a small, simple, and ultrafast web framework for the Edges. It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Netlify, AWS Lambda, Lambda@Edge, and Node.js.

In this case we use hono middlewares with remix and cloudflare.

Setup Hono

How to implement remix-hono lib for remix app. First we have to install npm i remix-hono and create the following file:

// server/index.ts
import { EnvSchema } from "./env";

import { logDevReady } from "@remix-run/cloudflare";
import * as build from "@remix-run/dev/server-build";
import { Hono } from "hono";
// You can also use it with other runtimes
import { handle } from "hono/cloudflare-pages";
import { remix } from "remix-hono/handler";
import { basicAuth } from "hono/basic-auth";

if (process.env.NODE_ENV === "development") logDevReady(build);

/* type your Cloudflare bindings here */
type Bindings = {};

/* type your Hono variables (used with c.get/c.set) here */
type Variables = {};

type ContextEnv = { Bindings: Bindings; Variables: Variables };

const server = new Hono<ContextEnv>();

server.use("*", basicAuth({ username: "hono", password: "remix" }));

server.use(
  "*",
  remix({
    build,
    mode: process.env.NODE_ENV as "development" | "production",

    getLoadContext(ctx) {
      const env = EnvSchema.parse(ctx.env);
      const response = {
        env,
        db: ctx.env.DB,
      };
      return response;
    },
  })
);

export const onRequest = handle(server);

Setup Envs variables

Our environment variables will be in the file .dev.vars for example:

DB="postgresql://saasa:url-database/sarasa?sslmode=require"

Then we create a env.ts file

// server/env.ts
import { z } from "zod";

export const EnvSchema = z.object({
  DB: z.string().min(1),
});

export type Env = z.infer<typeof EnvSchema>;

Setup Remix config

For our remix app to start with hono we have to change the server in remix.config.js:

/** @type {import('@remix-run/dev').AppConfig} */
export default {
  ignoredRouteFiles: ["**/*.css"],
  server: "./server/index.ts", // run with hono config
  watchPaths: ["./server/**/*.ts"],
  serverBuildPath: "functions/[[path]].js",
  serverConditions: ["worker"],
  serverDependenciesToBundle: "all",
  serverMainFields: ["browser", "module", "main"],
  serverMinify: true,
  serverModuleFormat: "esm",
  serverPlatform: "neutral",
  serverNodeBuiltinsPolyfill: { modules: {} },
};

Using Envs

And that is the basic configuration, if you want to use your environment variable (in this case db). You can do something like this:

export const loader = async ({ context }: LoaderFunctionArgs) => {
  const hotels = await queryHotels(context);

  return json({ hotels });
};

queries file:

import { neon } from "@neondatabase/serverless";
import { AppLoadContext } from "@remix-run/cloudflare";
import { database } from "db/db.server";

export async function queryHotels(context: AppLoadContext) {
  const db = database(neon(context.db as string));
  const hotels = await db.query.hotels.findMany();
  return hotels;
}

and databse config:

export function database(neon: any) {
  return drizzle(neon, {
    schema: {
      hotels: hotelsTable,
    },
  });
}

End

Thank you very much for reading and I hope you found it helpful.