Remix v2 のルーティングにおける flat-routes と Dot Delimiters
Remix v2 の学習において、個人的に詰まった点の備忘録として。
要約
- Remix v2 のルーティングには flat-routes がデフォルトで採用されている。
- そのため、Remix v2 ではページファイルを app/routes の直下に格納する。
- tsx のファイル名(もしくはディレクトリ名)に、ドット(
.
)を含めるとドットが URL の / として扱われる。 - > Dot Delimiters
- tsx のファイル名(もしくはディレクトリ名)に、ドット(
- 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 // ← 新規追加
各ファイルの内容はこんな感じです。
import { Outlet } from "@remix-run/react";
export default function Post() {
return (
<div>
<h1>This is Post</h1>
<Outlet />
</div>
);
}
import { Outlet } from "@remix-run/react";
export default function PostHoge() {
return (
<div>
<h2>Hoge Page</h2>
<Outlet />
</div>
);
}
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/hoge | app/routes/post.hoge.tsx | |
localhost:3000/post/hoge/fuga | app/routes/post.hoge.fuga.tsx |
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
各ファイルの内容はこんな感じです。
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>
);
}
export const Header = () => {
return (
<header>
<p>Header</p>
</header>
);
};
export const Footer = () => {
return (
<footer>
<p>Footer</p>
</footer>
);
};
export default function AboutIndex() {
return (
<div>
<h2>About Index Page</h2>
</div>
);
}
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/hoge | app/routes/about.hoge/index.tsx |
この場合、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 に記載してある内容と同じ事をやっているだけですね。
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