Next.jsのParallel Routesでslotのloading.tsxが正常に表示されなかった話
TL;DR
- Next.js の Parallel Routes を 14.1.1-canary.14 以前で使うと一部の slot の loading.tsx しか表示されない
- 次回の安定版で修正される予定
前提条件
Parallel Routes は Next.js の App Router で提供されている機能ですので、以降の文章は App Router を前提として進めさせて頂きます。
Parallel Routes とは何か
Next.js では一つの layout.tsx 内に複数のページを同時かつ条件付きでレンダリングするための仕組みとしてParallel Routesという仕組みが提供されています。
具体的にどのような機能かを説明していきます。
app/配下に以下のようなディレクトリを構築したとします。
.
├── dashboard
│ ├── @books
│ │ ├── loading.tsx
│ │ └── page.tsx
│ ├── @customers
│ │ ├── loading.tsx
│ │ └── page.tsx
│ ├── @sales
│ │ ├── loading.tsx
│ │ └── page.tsx
│ ├── default.tsx
│ ├── layout.tsx
│ ├── loading.tsx
│ └── page.tsx
├── favicon.ico
├── globals.css
├── layout.tsx
└── page.tsx
注目して頂きたいのは @books
など先頭に@がついたディレクトリです。
Next.js では先頭に@が付いたディレクトリを Slot と呼び、親ディレクトリの layout.tsx 内で props として渡されます。
app/layout.tsx で以下のように書くことで各 Slot 内の page.tsx を呼び出すことができます。
export default function Layout({
children,
books,
customers,
sales,
}: {
children: React.ReactNode;
books: React.ReactNode;
customers: React.ReactNode;
sales: React.Sales;
}) {
return (
<>
{children}
{books}
{customers}
{sales}
</>
);
}
Parallel Routes が面白いのは各 Slot は Page と同じように loading.tsx や error.tsx を配置することで Loading 状態やエラー時の UI を管理できる点です。
現時点で Slot でサポートされているファイルは以下の 5 つです *1
- page.tsx
- loading.tsx
- error.tsx
- default.tsx
- (layout.tsx)
- #61115 parallel routes: support multi-slot layouts がリリースされ次第でサポート予定
*1... https://github.com/vercel/next.js/issues/58506#issuecomment-1884106626
上記の例では@books・@customers・@sales の Slot に loading.tsx が配置しています。
そのため Next.js を localhost:3000 で立ち上げた場合 http://localhost:3000/dashboard にアクセスすると最初は@books・@customers・@sales 計 3 つの loading.tsx が表示される事になります。
遭遇した現象
自分が遭遇したのは一部の Slot の loading.tsx しか表示されないというものでした。
再現環境
https://parallel-routes-bug.vercel.app/dashboard
リポジトリ
https://github.com/Katsukiniwa/parallel-routes-bug
今回 app/dashboard 配下に book, customers, sales の 3 つの slot を loading.tsx と page.tsx を置いた上で作成しました。
期待する動作は全 Slot の loading.tsx が表示される事です。具体的にはLOADING Books...
と LOADING Customers...
と LOADING Sales...
の 3 つが表示される事です。
しかし、上記の再現環境にアクセスして頂くとLOADING Customers...
と LOADING Sales...
しか表示されません。
ちなみに loading 完了後は以下のように表示されます。
どうしたか
試行錯誤した挙句 Next.js 側のバグである可能性を考え最新の canary 版(v14.1.1-canary.82)を試したところ期待する動作を確認できました。あとは 2 分探索の要領でどの canary 版で修正されたのかを探し、v14.1.1-canary.15 で修正されていることを特定しました。v14.1.1-canary.15 に含まれている parallel routes に関する修正 PR は https://github.com/vercel/next.js/pull/61115 だけでした。この PR の詳細を理解することはできませんでしたが、タイトルから推察するに Slot で layout.tsx をサポートする feature PR のようです。なぜこの PR で今回の現象が修正されたのかは謎ですが、ひとまず修正されていることが確認できて安心しました。
最後に
一応上記の再現環境とリポジトリを作成した上で issue を立てたところ、この現象については修正済みであり、次の安定版でリリースされることをメンテナの方から教えて頂きました。
Next.js の素晴らしいサポートに感謝しかありません 🙏
https://github.com/vercel/next.js/issues/62722#issuecomment-1973356698
Discussion