Skip to content
返回技术栈推荐

Remix Web 标准应用

Remix 搭配嵌套路由、渐进增强和 Web Fetch API — 基于 Web 标准。

全栈中等

技术栈组成

FrameworkRemix 2.15
DataLoaders + Actions
DBSQLite (Turso) + Drizzle
StylingTailwindCSS 4
FormsRemix <Form> + useActionData
DeployFly.io / Vercel

为什么

Remix 用 Web 标准(Fetch API、Request/Response),代码在 Workers、Node、Deno 不变运行。嵌套路由并行加载数据。

渐进增强:表单无 JS 可用,水合后 SPA 体验。

何时使用

选择 Remix 用于 Web 标准主义者、部署到多运行时的应用和表单密集 CRUD 应用。需要 React Server Components 避免(用 Next.js),纯静态输出避免(用 Astro)。

如何做

1. 脚手架 — npx create-remix@latest myapp --template remix-run/remix/templates/remix 2. 路由 — app/routes/ 中基于文件,无路径路由做嵌套布局 3. loader — export async function loader({ request }) 返回 JSON,服务端运行 4. action — export async function action({ request }) 处理 POST/PUT/DELETE 5. 表单 — <Form method="post"> 配 useActionData 处理错误,无 JS 可用 6. 嵌套路由 — 父 outlet 渲染子路由,并行数据加载 7. 错误边界 — 每路由 export function ErrorBoundary,隔离故障 8. 部署 — fly.io(推荐),或 Vercel/Cloudflare/Node 适配器

示例

// app/routes/users.tsx — 嵌套路由带 loader import { json, type LoaderFunctionArgs } from "@remix-run/node"; import { useLoaderData, Form, useActionData } from "@remix-run/react"; import { drizzle } from "drizzle-orm/libsql"; const db = drizzle(process.env.TURSO_URL!); export async function loader({ request }: LoaderFunctionArgs) { const users = await db.select().from(usersTable).limit(20); return json({ users }); } export async function action({ request }: LoaderFunctionArgs) { const formData = await request.formData(); const email = String(formData.get("email")); const name = String(formData.get("name")); if (!email.includes("@")) { return json({ error: "邮箱无效" }, { status: 400 }); } await db.insert(usersTable).values({ email, name }); return json({ ok: true }); } export default function Users() { const { users } = useLoaderData<typeof loader>(); const actionData = useActionData<typeof action>(); return ( <div> <h1>用户({users.length})</h1> <ul>{users.map((u) => <li key={u.id}>{u.name} — {u.email}</li>)}</ul> <Form method="post"> {actionData?.error && <p style={{ color: "red" }}>{actionData.error}</p>} <input name="email" type="email" required /> <input name="name" required /> <button type="submit">添加用户</button> </Form> </div> ); } // app/routes/users.$id.tsx — 嵌套子路由 export async function loader({ params }: LoaderFunctionArgs) { const user = await db.select().from(usersTable).where(eq(usersTable.id, params.id)); if (!user[0]) throw new Response("未找到", { status: 404 }); return json({ user: user[0] }); }

常见问题

  • ⚠loader 每次导航都运行 — 用 Cache-Control 头,非客户端缓存
  • ⚠Form 无 method — 默认 GET(loader),action 用 method='post'
  • ⚠throw vs return json 错误 — throw Response 触发 ErrorBoundary,return 内联显示
  • ⚠loader 中 session — 用 cookie session,非服务端内存(多实例安全)

最佳实践

  • ✓渐进增强优先 — <Form> 无 JS 可用,用 useFetcher 增强
  • ✓布局用嵌套路由 — 父加载外壳,子并行加载内容
  • ✓loader 中用 Cache-Control — Remix 尊重它,边缘免费缓存
  • ✓每路由错误边界 — 隔离故障,父路由保持交互

常见问题解答

什么是Remix Web 标准应用?适合做什么项目?

Remix 搭配嵌套路由、渐进增强和 Web Fetch API — 基于 Web 标准。 它通过分层组合提供端到端类型安全与开箱即用的部署体验,适合从 MVP 到生产 SaaS 的快速迭代。

如何用Remix Web 标准应用在 10 分钟内跑通一个 demo?

两步起步:① 脚手架 — npx create-remix@latest myapp --template remix-run/remix/templates/remix;② 路由 — app/routes/ 中基于文件,无路径路由做嵌套布局。先跑通本地 dev server,再接一个真实数据源验证端到端链路。

Remix Web 标准应用 最常见的坑是什么?怎么避免?

最高频的坑是:loader 每次导航都运行 — 用 Cache-Control 头,非客户端缓存。避免方法:在 PR 模板里加入对应 checklist,CI 中跑类型检查 + lint + 单测,三重把关再合并。

Remix Web 标准应用 的最佳实践有哪些?

Remix Web 标准应用 的最佳实践包括:渐进增强优先 — <Form> 无 JS 可用,用 useFetcher 增强;布局用嵌套路由 — 父加载外壳,子并行加载内容;loader 中用 Cache-Control — Remix 尊重它,边缘免费缓存。其中首条「渐进增强优先 — <Form> 无 JS 可用,用 useFetcher 增强」应在项目初始化时就落地,避免后期返工。

什么情况下不该选Remix Web 标准应用?

三种情况另选他栈:① 团队对该栈核心框架零经验且工期紧张(学习曲线风险);② 项目是纯内容/营销站(选 Astro 更轻);③ 需要极高吞吐(>1 万 RPS)或强一致微服务(选 Go/Rust)。Remix Web 标准应用 的强项是中高复杂度全栈与 API,别在简单静态页上过度工程。