🧐

App Router のRoutingについて考察

2023/10/24に公開

はじめに

だいぶ App Router に慣れてきたので、便利なところと、おや?と思うところを整理したいと思います。今回は Routing についてのご紹介・考察です。

https://nextjs.org/docs/app/building-your-application/routing/colocation

基本的な Routing のおさらい

公式

/src
    /app
        /dashboard
            /page.tsx
            /settings
                /page.tsx
    /api
        /route.ts

というような構成にすることで、

/dashboard
/dashboard/settings
/api

という具合に非常に簡単かつ直感的な Routing を実現できます。

Routing の機構

公式を見てみると、他にも機構があるようなので、ご紹介します。今回は以下の 3 つを取り上げて、それぞれについて、使い勝手の良さとか感想をお伝えします。あくまで個人の見解です。

1. Route Groups

公式

/src
    /app
        /(user)
            /dashboard
                /page.tsx
            /profile
                /page.tsx
            /layout.tsx  <- /dashboard, /profile に適用されるレイアウト
        /(admin)
            /setting
                /page.tsx
            /users
                /page.tsx
            /layout.tsx  <- /setting, /users に適用されるレイアウト

個人的に衝撃を受けた機構ですが、(xxx) という命名規則でフォルダを作成することで その配下のフォルダをくくることができます。
例えば、上記のように user 用と admin 用で画面のレイアウトを分けたい場合、または画面によって、ナビゲーションの表示有無を分けたい場合などが挙げられます。

画面レイアウトの統制の取りやすさが大きな利点だと考えます。

2. Module Path Aliases

公式

/src/app/aaa/bbb/ccc/ddd/page.tsx
// before
import { Button } from "../../../../components/ui";

// after
import { Button } from "@/ui";

使用したいコンポーネントを import する際に、絶対パスや相対パスで指定することがあると思いますが、page.tsx が Routing を担っている関係で、とても深い階層からの呼び出しがされることが起こり得ます。そういった場合に、有効なのが、この機構です。

Module Path Aliases にあるように、とても簡単に設定できますが、
create-next-app コマンドを使って、プロジェクトを新規作成する場合は、

What is your project named?  my-app
Would you like to use TypeScript?  No / Yes
Would you like to use ESLint?  No / Yes
Would you like to use Tailwind CSS?  No / Yes
Would you like to use `src/` directory?  No / Yes
Would you like to use App Router? (recommended)  No / Yes
Would you like to customize the default import alias (@/*)?  No / Yes

このように対話的に設定が可能になっています。

import 文は他の言語でもそうですが、読みづらくなる傾向があるように思えます。開発端末の解像度がよくないと PR では見切れたり、折り返しになったりすることもあるので、そこを端的に表現できるようになるのは、レビュー観点で嬉しい利点だと考えます。

3. Private Folders

公式

/src
    /app
        /dashboard
            /page.tsx
            /_components <- この配下はRoutingされない
                /index.ts
                /DashboardContainer.tsx
                /DashboardPresenter.tsx

というように、フォルダ名の接頭辞に _ を付与したフォルダにすることで、/_components 配下を Routing から除外することができます。
これにより意図しない Routing がされないのですが、private folder に配置するものには注意が必要かと思いました。

まずはじめに考えたいのが、ボタンやタブといった他のページからも共有して参照する UI コンポーネントです。これは、ほぼ自明ですが、これらを private に配置すると、他が参照すると構成が歪になるので、避けるべきだと思います。

もう一つは、そのページ固有のコンポーネントです。上記は、ページを構成するコンポーネントを配置した例です。中身は省略しますが、責務分割すると

ページの Routing が責務

/src/app/dashboard/page.tsx
import { Dashboard } from './_components';

export default Dashboard;

ページで扱うデータの加工が責務

/src/app/dashboard/_components/index.ts
export { DashboardContainer as Dashboard } from './_components/DashboardContainer';
/src/app/dashboard/_components/DashboardContainer.tsx
import { DashboardPresenter } from './_components/DashboardPresenter';

export const DashboardContainer = () => {
  ...

  return <DashboardPresenter {...} />
}

ページの UI 決定が責務

/src/app/dashboard/_components/DashboardPresenter.tsx
export const DashboardPresenter = () => <div>Dashboardのページです</div>

というようになります。責務については、以前まとめたものがあるので、よければご覧ください。
https://zenn.dev/ficilcom/articles/app_router_design_pattern

ページ固有なものなので、全く問題ないでしょう。公式にもあるように、標準的な使い方であり、弊社のプロジェクトでも採用している構成ルールです。

なんですが、私の得意とする分野がリファクタリングとか仕様変更容易性といった領域なので、その観点で見たときに、最近 違和感を覚え始めました。というのも、page.tsxApp router から導入された仕様であり、また新たな Routing 方法が導入されたときに、_components 配下のフォルダ移動を余儀なくされます。「たかが、フォルダ移動なので、それくらいやれば?」という意見は多いと思いますが、しなくていい改修はしない方がいいかと今は思っています。ページ数が巨大になれば、こういうリファクタリングコストが顕著に現れてきます。

まだ検討段階ですが、

/src
    /app
        /dashboard
            /page.tsx
    /components
        /page
            /Dashboard
              /index.ts
              /DashboardContainer.tsx
              /DashboardPresenter.tsx
        /ui
            /Button.tsx
            /Tabs.tsx

という構成にすることで、 page.tsx による Routing が変更になったとしても、 /components/page/ 配下は無用なリファクタリングをすることなく継続的に使用することができます。

まとめ

さまざまな機構があり、便利なものもありますが、private folder って使う場面ないんじゃないかなあと思っています。あくまで個人の見解です。

フロントエンドの開発は、瞬く間にバージョンアップされる傾向があり、NextJs 14 へのバージョンアップも近々起こりそうな予感がしています(2023/10/24 現在)。フロントエンドの中枢となる部分が、フレームワークに依存しない構成であれば、バージョンアップの気軽さ、だけでなく開発の生産性も向上するのではないかと考えます。

GitHubで編集を提案
フィシルコム

Discussion