Remix + Hono
Remix 是一个用于构建 Web 应用程序的 Web 框架,可以在边缘运行。
Hono 是一个用于边缘的小巧且超快的 Web 框架。
此适配器允许您将 Hono 与 Remix 一起使用,以便您可以使用两者各自的优势。
让 Hono 为您的 HTTP 服务器及其中间件提供动力,然后使用 Remix 构建您的 Web 应用程序。
安装
安装包
npm add remix-hono
以下包是可选依赖项,您需要根据您正在使用的 remix-hono 功能来安装它们。
- 如果您使用 Cloudflare 集成,则使用
@remix-run/cloudflare
。 - 如果您使用 i18n 中间件,则使用
i18next
和remix-i18next
。 - 如果您使用
typedEnv
,则使用zod
。
[!注意] 如果您不使用这些包,实际上不需要安装它们,但是如果您使用依赖于这些包的功能,则需要自行安装它们(它们不会自动安装)。
使用
创建您的 Hono + Remix 服务器
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";
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 Remix middleware to your Hono server
server.use(
"*",
remix({
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: "remix" }),
// Ensure Remix request handler is the last one
remix(options),
);
仅此而已,您的应用程序现在将具有基本身份验证保护,这非常适合预览应用程序。
会话管理
除了 remix
Hono 中间件之外,还有另外三个中间件可用于处理 Remix 会话。
由于 Remix 会话通常使用来自环境的密钥,因此您需要访问 Hono c.env
以使用它们。如果您使用 Worker KV 会话存储,则还需要将 KV 绑定传递到中间件。
您可以使用此包中包含的不同中间件来执行此操作
import { session } from "remix-hono/session";
// Install the `@remix-run/*` package for your server adapter to grab the
// factory functions for session storage
import { createWorkerKVSessionStorage } from "@remix-run/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],
},
});
},
}),
);
现在,在您的会话中间件之后设置 Remix 中间件,并使用辅助函数 getSessionStorage
和 getSession
来访问 SessionStorage 和 Session 对象。
注意 只有在会话中间件选项中将 autoCommit 设置为 true 时,Session 对象才会被定义。如果将其设置为 false,则需要手动调用
sessionStorage.getSession()
。
import { getSessionStorage, getSession } from "remix-hono/session";
server.use(
"*",
remix<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
中间件用于此目的。
如果您尚未安装 @remix-run/cloudflare
,请先安装它。
npm add @remix-run/cloudflare
然后在您的服务器中使用中间件。
import { staticAssets } from "remix-hono/cloudflare";
import { remix } from "remix-hono/handler";
server.use(
"*",
staticAssets(),
// Add Remix request handler as the last middleware
remix(options),
);
i18next 集成
如果您使用 remix-i18next 来支持 Remix 应用程序中的 i18n,则 i18next
中间件允许您将其设置为中间件,您可以在以后的 getLoadContext
函数中使用它来将 locale
和 t
函数传递给您的加载器和操作。
如果您还没有安装 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(
"*",
remix({
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 许可证