🎉

Next.jsのParallel Routesでslotのloading.tsxが正常に表示されなかった話

2024/03/02に公開

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

*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 を置いた上で作成しました。

directory.png

期待する動作は全 Slot の loading.tsx が表示される事です。具体的にはLOADING Books...LOADING Customers...LOADING Sales... の 3 つが表示される事です。

しかし、上記の再現環境にアクセスして頂くとLOADING Customers...LOADING Sales... しか表示されません。

loading-bug

ちなみに loading 完了後は以下のように表示されます。

loading-complete

どうしたか

試行錯誤した挙句 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

GitHubで編集を提案

Discussion