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 中介軟體,則需要
i18next
和remix-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 中介軟體,並使用輔助函式 getSessionStorage
和 getSession
來存取 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];
},
},
}),
);
在 workerKVSession
和 cookieSession
中,您可以使用從 remix-hono/session
匯入的 getSession
和 getSessionStorage
。
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
函式中使用它,以將 locale
和 t
函式傳遞給您的 loaders 和 actions。
如果尚未安裝,請先安裝 i18next
和 remix-i18next
。
npm add i18next remix-i18next
然後在您的伺服器中使用中介軟體。
import { i18next } from "remix-hono/i18next";
// Same options as in remix-i18next
server.use("*", i18next(options));
然後,在您的 getLoadContext
函式中,您可以使用輔助函式 i18next.getLocale
和 i18next.getFixedT
來存取 locale
和 t
函式。
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 授權