next.js 13.4のblogのapp routerについて要約
以前まではpages routerという仕組みが、app routerという機構となり、さらにstableとなった。
本記事は、next.jsを昔ちょろっと触ったことのある程度の筆者の、メモの役割程度のものなので、より詳しい情報が知りたい人は原文を読んでほしい。
以下本文となります。
app routerではnext.jsの4つのprinciples:
- Zero setup. Use the filesystem as an API
- Only JavaScript. Everything is a function
- Automatic server rendering and code splitting
- Data fetching is up to the developer
に近づくための機能が提供される。
zero config
next.jsはページ全体の共通の設定などをpages/_app.jsとpages/_document.jsで設定していた。
_app.jsにはlayout定義やglobalな状態管理のためのコンポーネントを用いたラップなどを行う。RecoilRootなどもここに記述する。
_document.jsにはhtllタグやheadタグなどを記述する。
app routerではこの2つの設定ファイルを記述する必要がなくなった。
ではどのように変わったのか。
まず、layoutをfolderごとに定義できるようになった。app/があったとき、app/layout.jsをrootのlayoutとして定義すると、app/page.jsではそのレイアウトが適用される。rootのlayoutではhtmlタグなどを記述し、これは_document.jsの代わりとなる。
また、layoutはnestすることができ、app/dashboard/layout.jsを定義すれば、それはdashboard/以下のcomponent用のlayoutとなる。
only JavaScript. Everything is a function
今まではgetStaticPropsなどdata fetch用の関数をapp/fetch.jsのような外部ファイルに書き出し、componentの記述と分離していた。fetchしたデータはpropsバケツリレーでcomponentに渡していた。
また、getStaticPropasやgetServerSidePropsを明示的に書くことで、data fetchをどこで実行(例:クライアントかサーバーか)するかをnext.jsがよしなに最適化してくれていた。
しかしそれはnext.jsの都合であり、”just JavaScript”の原則に反している。
そこでapp routerでは、component内でのfetchの記述が可能となっている。これによりバケツリレーも減少し、記述は楽になる。
また、デフォルトでcomponentはReact Server Componentsのため、fetchはserver上で実行される。サーバーサイドでのfetchが主となることに付随するキャッシュ戦略などの変化については他の記事を参照されたい。(自分もそのレベルの解釈ができるレベルではない)
Data fetching is up to the developer
fetchがcomponent内で記述でき、かつserver上で実行されるため、data fetching is up to the developerの原則にもより近づく。
そもそもこの原則は、開発者がより柔軟にfetchを行えるのがいいよねということなので、どんなcomponentでもfetchができるこの機能はよりイケてるよねってことを言いたいんだと思う。(ここは自分でも理解があやふやなので主観です)
例えばreact-tweetのようなサードパーティーのcomponentを用いるときでも、server上でのfetchが保証される。
Automatic server rendering and code splitting
next.jsが出た当初、renderingやcode splittingの最適化はwebpackなどさまざまなエコシステテムを用いてプロが職人技を披露するといったことが一般的だった。そういった職人技のコストを減らすため、最適化をよしなに行ってくれるいくつかの機能を提供しており、route-basedなcode splittingはその一つである。これは名前の通りpages/ 以下のディレクトリがJS bundleとして分割され、初期表示を高速化する。(単一のドデカjsを読み込まなくて済む)
ただしディレクトリ単位だけでは最適化のプロたちは満足せず、component単位でもcode splittingを行えないかと考えられた。
もちろんnext.jsはそのための機能を提供していたが、next/dynamiからdynamicと呼ばれる関数を呼び出し、その関数に明示的にcomponentを渡してあげる必要があった。
app routerでは、そもそもreact server componetsをデフォルトで利用するためclientのためにjsをbundleすることを考えなくて良い。
またclientのcomponentはwebpack/Turbopackによって自動でsplitされる。
さらにapp routerはreact suspense (loading時などに、componentのハンドリングを担当してくれる)を統合しているので、`return isLoggedIn ? <Dashboard /> : <Landing />;`のようにconditionalに、loadingの状態をcode split付きで制御できる。
以上