mcpField
R
remix-v2-routing

remix-v2-routing

github.com/existential-birds开发8540 次安装11 周前更新
代码仓库

关于 remix-v2-routing

面向 Remix v2 开发者的路由技能,说明 flat-routes 文件命名、嵌套路由及资源路由规则。通过决策步骤帮助选择布局、URL 结构和路由类型。

主要功能

  1. 01解释 flat-routes 文件命名规则
  2. 02配置嵌套与无路径布局
  3. 03处理动态片段与通配路径
  4. 04区分 UI 路由和资源路由
  5. 05提供 v1 到 v2 约定对照

适用场景

  1. 01规划共享导航的嵌套路由
  2. 02为登录页设置无路径布局
  3. 03创建动态 URL 或通配路径
  4. 04为 JSON、PDF 或 Webhook 创建资源路由

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/existential-birds/beagle --skill remix-v2-routing

安装后在 Claude Code 中输入/remix-v2-routing确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
conventions.md
resource-routes.md
root.md
v1-migration.md

详细介绍

Remix v2 路由

快速参考

Flat-routes v2 文件名规则(所有文件都位于 app/routes/):

_index.tsx                 → /
concerts.tsx               → /concerts                (acts as layout when dotted children exist; otherwise leaf for /concerts)
concerts._index.tsx        → /concerts                (renders under layout)
concerts.$city.tsx         → /concerts/:city          params.city
concerts.trending.tsx      → /concerts/trending
_auth.tsx + _auth.login.tsx → /login (pathless layout, no URL segment)
files.$.tsx                → /files/*                 params["*"]
($lang)._index.tsx         → / and /en (or /fr etc.) — optional segment
sitemap[.]xml.tsx          → /sitemap.xml             (escape literal)
concerts_.mine.tsx         → /concerts/mine           (opts out of layout)
dashboard/route.tsx        → /dashboard               (folder + route.tsx)
reports.$id[.pdf].tsx      → /reports/:id.pdf         (no default export = resource)

导入 — 始终使用 @remix-run/react,不要使用 react-router-dom:

import { Outlet, Link, useLoaderData, useParams } from "@remix-run/react";
import type { LoaderFunctionArgs } from "@remix-run/node"; // or /cloudflare, /deno

文件命名约定

文件名中的点会创建 URL 斜杠以及父子嵌套。下划线前缀表示无路径片段(_auth.tsx)和索引路由(_index.tsx)。尾随下划线(concerts_.mine.tsx)可退出布局嵌套,同时保留 URL 嵌套。方括号用于转义字面字符:sitemap[.]xml.tsx。Splat 是单个美元符号:$.tsx 会通过 params["*"] 暴露路径剩余部分。可选片段用括号括起:($lang)。

完整表格及边缘情况请参阅 references/conventions.md。

嵌套布局

父模块(concerts.tsx)会渲染 <Outlet />;子路由(concerts.$city.tsx、concerts._index.tsx)会根据以点分隔的文件名自动挂载到其中。

// app/routes/concerts.tsx
import { Outlet } from "@remix-run/react";

export default function ConcertsLayout() {
  return (
    <section>
      <nav>{/* concerts subnav */}</nav>
      <Outlet />
    </section>
  );
}
// app/routes/concerts._index.tsx  (renders at exactly /concerts)
export default function ConcertsIndex() {
  return <h1>Browse concerts</h1>;
}

对于不贡献 URL 的布局,请加上单个下划线前缀:

// app/routes/_auth.tsx          → wraps /login, /signup; no URL segment
// app/routes/_auth.login.tsx    → /login   (inherits _auth layout)
// app/routes/_auth.signup.tsx   → /signup

动态片段和 Splat

$name 捕获单个片段;$.tsx 捕获路径剩余部分。Loader 通过 params 接收值:

// app/routes/concerts.$city.tsx
import type { LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";

export async function loader({ params }: LoaderFunctionArgs) {
  if (!params.city) throw new Response("Not found", { status: 404 });
  return json({ city: params.city });
}

export default function City() {
  const { city } = useLoaderData<typeof loader>();
  return <h1>{city}</h1>;
}

Splat 值存放在 "*" 下——没有 params.splat:

// app/routes/files.$.tsx
export async function loader({ params }: LoaderFunctionArgs) {
  const rest = params["*"]; // bracket access only
  return new Response(await readBlob(rest), { headers: { "Content-Type": "application/octet-stream" } });
}

根模块

app/root.tsx 是唯一必需的路由。它负责文档外壳,并且必须渲染 <Meta />、<Links />、<Outlet />、<ScrollRestoration />、<Scripts />,以及(开发期间的)<LiveReload />。请参阅 references/root.md。

资源路由

没有 default 导出的路由模块是资源路由——它会返回原始 Response 对象(PDF、JSON、RSS、webhook)。父级 loader 不会运行,并且必须在 <Link> 中使用 reloadDocument(或改用 <a>)才能触发真正的文档请求。请参阅 references/resource-routes.md。

判定步骤(决策顺序)

按顺序回答。通过表示条件为真;选择同一行的答案并停止。

布局还是扁平 URL
  1. 此层级是否存在任何共享界面元素(导航、面包屑、侧边栏)?
    • 未通过 → 使用普通的点分隔片段(about.tsx、pricing.tsx);无需布局模块。停止。
    • 通过 → 第 1 步。
  2. 此 URL 是否应与父路径共享界面(导航、面包屑、侧边栏)?
    • 通过 → 使用点分隔嵌套(在 concerts.tsx 下放置 concerts.$city.tsx)。停止。
    • 未通过 → 第 2 步。
  3. URL 是否只是恰好嵌套,但应独立渲染?
    • 通过 → 使用尾随下划线(concerts_.mine.tsx)。停止。
    • 未通过 → 第 3 步。
  4. 是否需要包装布局,但不需要父级 URL 片段?
    • 通过 → 使用单下划线无路径父级(_auth.tsx + _auth.login.tsx)。停止。
UI 路由还是资源路由
  1. 此 URL 是否会向用户渲染 HTML?
    • 通过 → 导出一个 default 组件。即为 UI 路由。停止。
    • 未通过 → 第 2 步。
  2. 是否返回 JSON、PDF、RSS、sitemap、webhook 或其他原始 Response?
    • 通过 → 省略 default 导出——该模块会成为资源路由。在指向它的任何 <Link> 上使用 reloadDocument。停止。
_index.tsx 还是 index.tsx
  1. 是否使用带有 flat-routes 的 Remix v2?
    • 通过 → 使用 _index.tsx(前导下划线)。停止。
    • 未通过 → 第 2 步——你使用的是 v1(或 v1 回退适配器)。
  2. 是否需要保留 v1 嵌套文件夹结构?
    • 通过 → 安装 @remix-run/v1-route-convention 并在 remix.config.js 中接入。请参阅 references/v1-migration.md。停止。

其他文档

  • 约定:请参阅 references/conventions.md,了解完整的文件名语法(_index、_layout、$param、splat、可选、转义、文件夹 + route.tsx、尾随下划线)。
  • 根模块:请参阅 references/root.md,了解 root.tsx 脚手架和必需的文档元素。
  • 资源路由:请参阅 references/resource-routes.md,了解非 HTML 响应、禁止导出 default 的规则、跳过父级 loader,以及 reloadDocument。
  • v1 → v2 迁移:请参阅 references/v1-migration.md,了解与 v1 的差异(__double 下划线文件夹、index.tsx、@remix-run/v1-route-convention、ignoredRouteFiles)。

v1 与 v2 约定对比

关注点v1(嵌套文件夹)v2(扁平路由)
索引路由index.tsx_index.tsx
无路径布局__auth/(双下划线)_auth.tsx(单下划线)
嵌套 URL文件夹层级文件名中的点分隔符
动态片段$param.tsx$param.tsx(不变)
Splat$.tsx$.tsx(不变)
转义字面量不适用[.]、[] 方括号
退出布局移出文件夹尾随 _(foo_.bar.tsx)
文件共置文件夹中的相邻文件feature/route.tsx + 同级文件
回退适配器不适用@remix-run/v1-route-convention

评论

支持 Markdown