Remix/React Router + Hono

React Router 是一個用於建立 Web 應用程式的 Web 框架,可以在邊緣運行。

Hono 是一個用於邊緣的小巧且超快速的 Web 框架。

此轉接器允許您將 Hono 與 React Router 一起使用,因此您可以利用兩者的優勢。

讓 Hono 為您的 HTTP 伺服器及其 middleware 提供支援,然後使用 React Router 建立您的 Web 應用程式。

安裝

安裝套件

npm add remix-hono

以下套件是可選的依賴項,您需要根據您正在使用的 remix-hono 功能來安裝它們。

  • 如果您正在使用 Cloudflare 整合,則需要 @react-router/cloudflare
  • 如果您正在使用 i18n 中介軟體,則需要 i18nextremix-i18next
  • 如果您正在使用 typedEnv,則需要 zod

[!NOTE] 如果您不使用這些套件,則實際上不需要安裝它們,但是如果您使用依賴這些套件的功能,則需要自行安裝它們(它們不會自動安裝)。

使用方式

建立您的 Hono + React Routers 伺服器

import { logDevReady } from "@react-router/cloudflare";
import { Hono } from "hono";
// You can also use it with other runtimes
import { handle } from "hono/cloudflare-pages";
import { reactRouter } from "remix-hono/handler";

import build from "./build/server";

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>();

// Add the React Router middleware to your Hono server
server.use(
	"*",
	reactRouter({
		build,
		mode: process.env.NODE_ENV as "development" | "production",
		// getLoadContext is optional, the default function is the same as here
		getLoadContext(c) {
			return c.env;
		},
	}),
);

// Create a Cloudflare Pages request handler for your Hono server
export const onRequest = handle(server);

現在,您可以新增更多 Hono 中介軟體,例如基本驗證中介軟體

import { basicAuth } from "hono/basic-auth";

server.use(
	"*",
	basicAuth({ username: "hono", password: "react-router" }),
	// Ensure React Router request handler is the last one
	reactRouter(options),
);

僅僅這樣,您的應用程式現在將具有基本驗證保護,這對於預覽應用程式非常有效。

工作階段管理

除了 reactRouter Hono 中介軟體之外,還有其他三個中介軟體可用於處理 React Router 工作階段。

由於 React Router 工作階段通常使用來自環境的密鑰,因此您需要存取 Hono 的 c.env 才能使用它們。如果您正在使用 Worker KV 工作階段儲存,則還需要將 KV 綁定傳遞給中介軟體。

您可以使用此套件中包含的不同中介軟體來執行此操作

import { session } from "remix-hono/session";
import { createWorkerKVSessionStorage } from "@react-router/cloudflare";

server.use(
	"*",
	session({
		autoCommit: true,
		createSessionStorage(c) {
			return createWorkersKVSessionStorage({
				kv: c.env.MY_KV_BINDING,
				cookie: {
					name: "session",
					httpOnly: true,
					secrets: [c.SESSION_SECRET],
				},
			});
		},
	}),
);

現在,在您的工作階段中介軟體之後設定 React Router 中介軟體,並使用輔助函式 getSessionStoragegetSession 來存取 SessionStorage 和 Session 物件。

注意 只有在工作階段中介軟體選項中將 autoCommit 設定為 true 時,才會定義 Session 物件。如果將其設定為 false,則需要手動呼叫 sessionStorage.getSession()

import { getSessionStorage, getSession } from "remix-hono/session";

server.use(
	"*",
	reactRouter<ContextEnv>({
		build,
		mode: process.env.NODE_ENV as "development" | "production",
		// getLoadContext is optional, the default function is the same as here
		getLoadContext(c) {
			let sessionStorage = getSessionStorage(c);
			let session = getSession(c);

			// Return them here to access them in your loaders and actions
			return { ...c.env, sessionStorage, session };
		},
	}),
);

session 中介軟體是通用的,可讓您使用任何工作階段儲存機制。如果您想使用 Worker KV 工作階段儲存,則可以改用 workerKVSession 中介軟體。

import { workerKVSession } from "remix-hono/cloudflare";

server.use(
	"*",
	workerKVSession({
		autoCommit: true, // same as in the session middleware
		cookie: {
			name: "session", // all cookie options as in createWorkerKVSessionStorage
			// In this function, you can access c.env to get the session secret
			secrets(c) {
				return [c.env.SECRET];
			},
		},
		// The name of the binding using for the KVNamespace
		binding: "KV_BINDING",
	}),
);

如果您想使用 Cookie 工作階段儲存,則可以改用 cookieSession 中介軟體。

import { cookieSession } from "remix-hono/cloudflare";

server.use(
	"*",
	cookieSession({
		autoCommit: true, // same as in the session middleware
		cookie: {
			name: "session", // all cookie options as in createCookieSessionStorage
			// In this function, you can access c.env to get the session secret
			secrets(c) {
				return [c.env.SECRET];
			},
		},
	}),
);

workerKVSessioncookieSession 中,您可以使用從 remix-hono/session 匯入的 getSessiongetSessionStorage

Cloudflare 上的靜態資源

如果您正在使用 Remix Hono 和 Cloudflare,則需要從 public 資料夾(除了 public/build)提供靜態資源。staticAssets 中介軟體旨在實現此目的。

如果尚未安裝,請先安裝 @react-router/cloudflare

npm add @react-router/cloudflare

然後在您的伺服器中使用中介軟體。

import { staticAssets } from "remix-hono/cloudflare";
import { reactRouter } from "remix-hono/handler";

server.use(
	"*",
	staticAssets(),
	// Add React Router request handler as the last middleware
	reactRouter(options),
);

i18next 整合

如果您正在使用 remix-i18next 來支援 React Router 應用程式中的 i18n,則 i18next 中介軟體可讓您將其設定為 React Router 應用程式的中介軟體,您可以稍後在 getLoadContext 函式中使用它,以將 localet 函式傳遞給您的 loaders 和 actions。

如果尚未安裝,請先安裝 i18nextremix-i18next

npm add i18next remix-i18next

然後在您的伺服器中使用中介軟體。

import { i18next } from "remix-hono/i18next";

// Same options as in remix-i18next
server.use("*", i18next(options));

然後,在您的 getLoadContext 函式中,您可以使用輔助函式 i18next.getLocalei18next.getFixedT 來存取 localet 函式。

server.use(
	"*",
	reactRouter({
		build,
		mode: process.env.NODE_ENV as "development" | "production",
		// getLoadContext is optional, the default function is the same as here
		getLoadContext(c) {
			// get the locale from the context
			let locale = i18next.getLocale(c);
			// get t function for the default namespace
			let t = await i18next.getFixedT(c);
			// get t function for a specific namespace
			let errorT = await i18next.getFixedT(c, "error");
			return { env: c.env, locale, t, errorT };
		},
	}),
);

還有一個 i18next.get 函式,如果需要,它可以傳回 RemixI18Next 實例。

僅限 HTTPS

您可以使用 httpsOnly 中介軟體強制您的伺服器僅使用 HTTPS。

import { httpsOnly } from "remix-hono/security";

server.use("*", httpsOnly());

尾隨斜線

您可以使用 trailingSlash 中介軟體強制您的伺服器使用尾隨斜線。

import { trailingSlash } from "remix-hono/trailing-slash";

// By default, trailing slashes are disabled, so `https://company.tld/about/`
// will be redirect to `https://company.tld/about`
server.use("*", trailingSlash());
server.use("*", trailingSlash({ enabled: false }));

// You can also enable trailing slashes, so `https://company.tld/about` will be
// redirect to `https://company.tld/about/` instead
server.use("*", trailingSlash({ enabled: true }));

使用 Zod 的類型化環境

typedEnv 輔助函式可讓您取得任何執行階段的環境變數,並使用 Zod 根據結構描述驗證它。

如果尚未安裝,請先安裝 Zod。

npm add zod

然後在任何中介軟體或請求處理程式中使用輔助函式。

import { typedEnv } from "remix-hono/typed-env";

// Define your schema
const Schema = z.object({ SECRET: z.string() });

// Use the helper
server.get("/about", (c) => {
	let env = typedEnv(c, Schema);
	let secret = env.SECRET; // or typedEnv(c, Schema, "SECRET");
	// do something here
});

作者

授權

  • MIT 授權