レストランに例えて学ぶ Next.js の内部構造

## Next.js のコードを読んでみよう！
皆さんは Next.js を使っていて、その内部構造が気になったことはないですか？
私はあるんで、そのソースコードを読んでみて、何個かプルリクを送るようになりました。ただ全エンジニアが Next.js を理解するのに、いきなりソースコードを読むのは難しすぎると感じました。
なので、もっと簡単に Next.js の内部構造を説明してみようという！、というのがこの記事の意図です。
この記事が、Next.js のソースコードを読む一助になれば幸いです。

## Next.js をレストランに例えてみた
Next.js は、ファミレスのようなセントラルキッチン式のレストランに似ています。
セントラルキッチン式のレストランでは、以下の流れで最初に料理を作るからお客様に料理が届くまでします。

1. レストランとは別の位置にある外注の調理場で、料理を作る
2. 1で作った料理を冷蔵庫で冷凍し、レストランに運ぶ
3. お客様が来たら、ウェイターがお客様から注文を伺う
4. 2で作った料理を、炒めるか電子レンジで温める
5. 料理を運び、お客様に料理が届く

これがどうなれば、Next.js になるのでしょうか？
説明してみましょう！

#### 1. レストランとは別の位置にある調理場で、料理を作る
これは、Next.jsのプロジェクトで pages か app 配下に React のファイルを作る部分に当たります。
Create-react-app純製の React を使うなら、わざわざ「レストランとは別の位置にある調理場で、料理を作る」必要はありませんが、どの料理が出てくるか分からない（ユーザーがどのページを見るか分からない）ので全ての料理を作る必要があります（react-router で全ての `<Route>` を定義している部分）

https://qiita.com/jima-r20/items/c7d636262a9ebf0bedbd#react-router%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF

#### 2. 1で作った料理を冷蔵庫で冷凍し、レストランに運ぶ
ここでいう 冷蔵庫は webpack のことです。webpack とは Javascript のファイルの依存関係を解決し１つのファイルにまとめてくれるライブラリです。
Next.js のビルドフェーズ（`yarn dev`か`yarn build`）では、`.next`というフォルダに、Next.jsの設定（マニフェストファイル）や pages か app 配下にある Reactファイルをwebpackでbundleした結果（`.next/server/app/パス`などにある）が作られます。
アクセスが来る（お客様が来る）と、`.next`の中にあるマニフェストファイルが使用され、簡単に言えば bundleされたReactのファイルが送られます（後半 3以降）。

Next.js だと `packages/next/src/build` の配下の部分を指し、

https://github.com/vercel/next.js/blob/canary/packages/next/src/build/webpack-config.ts

などに主な設定があります。

#### 3. お客様が来たら、ウェイターがお客様から注文を伺う
ここは、アクセスが来た時にサーバーがパスを見ている部分です。
「お客様が来る」はアクセスが来たことを、「注文を伺う」はアクセスしてきたパス（`https://qiita.com/trend` なら `/trend` 部分）をサーバーが解析することを指します。
パスを見る時は、アクセスの来たパスが既存のものと一致するかどうかを判定し、一致するものがない場合は 404 を返します。

Next.js だと router-server.ts 

https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-server.ts

を起点にして、

https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts

https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/filesystem.ts

の主な２ファイルで、アクセスの来たパスが一致するかを判定しています。

#### 4. 3で伺ったメニューと合致する 2で作った料理を、炒めるか電子レンジで温める

3で一致したパスの React ファイルを、サーバーサイドでレンダーする部分がここに当たります。
ここでは、場合によっては2で作った料理以外の外注している料理を調達（外部APIへのリクエスト）して、料理を組み合わせることもできます。
炒めるか電子レンジで温めるかの前には、冷蔵庫からそれを取り出す部分もあると思いますが、それは

https://github.com/vercel/next.js/blob/canary/packages/next/src/server/load-components.ts

（loadComponents）で行っています。中身を見れば、getServerSideProps や getStaticProps を import しているのが分かると思います。

そこから実際に炒めたり電子レンジで温める部分が、app-router だと

https://github.com/vercel/next.js/blob/c623a3fa1f5ab226ef2aba2b2a827691033fd6a0/packages/next/src/server/app-render/app-render.tsx

pages-router だと

https://github.com/vercel/next.js/blob/c623a3fa1f5ab226ef2aba2b2a827691033fd6a0/packages/next/src/server/render.tsx

にあります。

<details><summary>呼び出し元はここら辺です</summary>

[findPageComponents](https://github.com/vercel/next.js/blob/b0c6b00643eedca2404b8f0eab0f09606ecab5eb/packages/next/src/server/base-server.ts#L2989) が loadModules を呼び出し、その先の renderToResponseWithComponents では page-router は [ここ](https://github.com/vercel/next.js/blob/b0c6b00643eedca2404b8f0eab0f09606ecab5eb/packages/next/src/server/base-server.ts#L2311-L2326) で、app-router は [ここ](https://github.com/vercel/next.js/blob/b0c6b00643eedca2404b8f0eab0f09606ecab5eb/packages/next/src/server/base-server.ts#L2327-L2346) で 呼び出されています。

</details>

#### 5. 料理を運ぶ、お客様に料理が届く

結果、アクセスしたクライアントに送り届ける部分です。
クライアントに届いてからは、料理が一人でに動き出すわけではない（再レンダー）ので、説明は省きます。

#### 追加説明

build の方をあまり見ることはないかもしれないので、server の方で説明を追加しますが、server は 

https://github.com/vercel/next.js/blob/canary/packages/next/src/server/base-server.ts

https://github.com/vercel/next.js/blob/canary/packages/next/src/server/web-server.ts

https://github.com/vercel/next.js/blob/canary/packages/next/src/server/next-server.ts

の継承関係で、中身が作られています。興味があったら、見てみてもいいかもしれません。
cli のエントリーポイントは

https://github.com/vercel/next.js/blob/c623a3fa1f5ab226ef2aba2b2a827691033fd6a0/packages/next/src/cli/next-dev.ts#L241

です。

## まとめ
Next.js を簡単にまとめると、build で Reactファイルを bundle して、router でどのReactファイルを表示するかを決めて（正確にいうと違いますが）、render でReactファイルを表示しています。
書きながら、普通のサーバーの説明と変わらないなと思いつつも、Next.js のソースコードリーディングも思っている以上に難しくなさそうだな、と思えてもらえたら嬉しいです。