🌳

Remix v2 のルーティングにおける flat-routes と Dot Delimiters

2024/01/21に公開

Remix v2 の学習において、個人的に詰まった点の備忘録として。

要約

  • Remix v2 のルーティングには flat-routes がデフォルトで採用されている。
  • そのため、Remix v2 ではページファイルを app/routes の直下に格納する。
    • tsx のファイル名(もしくはディレクトリ名)に、ドット(.)を含めるとドットが URL の / として扱われる。
    • > Dot Delimiters
  • remix-flat-routes を使って、ネストしたディレクトリ構造にもできる。
  • 公式サイトの Route File Naming に詳しい説明があるので、詳細な挙動を確認したい方はそちらをどうぞ。

Dot Delimiters

例えば、Remix v2 において app/routes 配下を以下のような構成にします。
post.tsx 達が新しく追加したファイルです。

./app
└── routes
    ├── _index.tsx
    ├── post.hoge.fuga.tsx // ← 新規追加
    ├── post.hoge.tsx // ← 新規追加
    └── post.tsx // ← 新規追加

各ファイルの内容はこんな感じです。

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

export default function Post() {
  return (
    <div>
      <h1>This is Post</h1>
      <Outlet />
    </div>
  );
}
app/routes/post.hoge.tsx
import { Outlet } from "@remix-run/react";

export default function PostHoge() {
  return (
    <div>
      <h2>Hoge Page</h2>
      <Outlet />
    </div>
  );
}
app/routes/post.hoge.fuga.tsx
export default function PostHogeFuga() {
  return (
    <div>
      <h3>Fuga Page</h3>
    </div>
  );
}

上記のディレクトリ構成で npm run dev コマンドを実行して localhost を立ち上げると、URL は以下のようになります。

URL 対応する tsx 画面
localhost:3000/post app/routes/post.tsx localhost:3000/post
localhost:3000/post/hoge app/routes/post.hoge.tsx localhost:3000/post/hoge
localhost:3000/post/hoge/fuga app/routes/post.hoge.fuga.tsx localhost:3000/post/hoge/fuga

Remix v2 では、app/routes 内のディレクトリ構造で URL を決めるのではなく、tsx のファイル名にドット(.)を入れて URL を決めていきます。
tsx ファイルの . が URL の / に相当します。

公式サイトの Dot Delimiters に詳細な説明があります。


また、tsx ファイルだけでなく、ディレクトリにも Dot Delimiters を適用できます。

例えば app/routes 配下を以下のような構成にします。
about ディレクトリ達が新しく追加したディレクトリとファイルです。

./app
└── routes
    ├── _index.tsx
    ├── about // ← 新規追加
    │   ├── footer.tsx
    │   ├── header.tsx
    │   └── route.tsx
    ├── about._index // ← 新規追加
    │   └── index.tsx
    ├── about.hoge // ← 新規追加
    │   └── index.tsx
    ├── post.hoge.fuga.tsx
    ├── post.hoge.tsx
    └── post.tsx

各ファイルの内容はこんな感じです。

app/routes/about/route.tsx
import { Header } from "./header";
import { Footer } from "./footer";
import { Outlet } from "@remix-run/react";

export default function About() {
  return (
    <div>
      <Header />
      <h1>This is About Route</h1>
      <Outlet />
      <Footer />
    </div>
  );
}
app/routes/about/header.tsx
export const Header = () => {
  return (
    <header>
      <p>Header</p>
    </header>
  );
};
app/routes/about/footer.tsx
export const Footer = () => {
  return (
    <footer>
      <p>Footer</p>
    </footer>
  );
};
app/routes/about._index/index.tsx
export default function AboutIndex() {
  return (
    <div>
      <h2>About Index Page</h2>
    </div>
  );
}
app/routes/about.hoge/index.tsx
export default function AboutHoge() {
  return (
    <div>
      <h2>About Hoge Page</h2>
    </div>
  );
}

上記の状態で npm run dev コマンドを実行して localhost を立ち上げると、about 関連の URL は以下のようになります。

URL 対応する tsx 画面
localhost:3000/about app/routes/about._index/index.tsx localhost:3000/about
localhost:3000/about/hoge app/routes/about.hoge/index.tsx localhost:3000/about/hoge

この場合、app/routes/about 配下のファイルが about 関連ページのレイアウトの元になっています。
localhost:3000/about でも localhost:3000/about/hoge でも、共通の header と footer が表示されているのが分かりますね。

remix-flat-routes

基本的に Remix v2 では、app/routes/ 直下にファイル・ディレクトリを追加していきます。
ただ規模が大きいプロジェクトですと、何十・何百というファイル・ディレクトリが app/routes/ 直下に格納されてしまいます。

これは remix.config.js にルーティングの設定を記載して回避することも可能ですが、今回は remix-flat-routes を使ってみます。

まずは npm i remix-flat-routes -D を実行します。

次に remix.config.js を以下のように編集します。
Configuration | remix-flat-routes に記載してある内容と同じ事をやっているだけですね。

remix.config.js
import { flatRoutes } from "remix-flat-routes"; // ← 新規追加

/** @type {import('@remix-run/dev').AppConfig} */
export default {
  ignoredRouteFiles: ["**/.*"],
  // …略…
  // ↓ 新規追加
  routes: async (defineRoutes) => {
    return flatRoutes("routes", defineRoutes);
  },
};

では、先程の about 関連のページを以下のように再配置してみます。

./app
└── routes
    ├── _index.tsx
    └── about
        ├── _index
        │   └── index.tsx
        ├── _layout.tsx
        ├── footer.tsx
        ├── header.tsx
        └── hoge
            └── index.tsx

変更点は以下の通りです。
再配置とリネームのみの対応であり、ファイルの中身に変更はありません。

  • app/routes/about/route.tsx を app/routes/about/_layout.tsx にリネーム。
  • app/routes/about._index/index.tsx を app/routes/about/_index/index.tsx に再配置。
  • app/routes/about.hoge/index.tsx を app/routes/about/hoge/index.tsx に再配置。

リネームと再配置が完了した状態で npm run dev を実行すると、先程と同じ URL 構成で about 関連ページが閲覧できます。
これで app/routes/ 配下にネストしたディレクトリ構成を作成できました。

ちなみに、remix-flat-routes は v0.5.1 から、プラス記号を使って flat-routes を実現できるようになっているようです。
> Nested folders with flat-files convention (✨ New in v0.5.1)

まとめ

今回の備忘録を作成した経緯ですが、
Remix v1 の解説記事を見ながら、Remix v2 をインストールして開発していて、「意図通りに動作しない!」とガン詰まりしていたのが、キッカケでした。
そりゃ〜うまく動作しないわけです。。

自分に対する戒めとして 「まず公式ドキュメントを読め!」 ですね。

Discussion