giraphme/blog

Next.js の App Router に移行する

このブログは Next.js でできていますが実装時点では SSG が未実装だったので、 pages ディレクトリを使用しています。 そして、先日晴れて v13.4 で安定版となり SSG もサポートされたので、 App Router への移行を試してみました。
基本的には Next.js のアップグレードガイドの通りですが、この中から SSG に関する変更のみを実例で解説します。

##トップページだけ移す

一部端折っていますが、このブログのトップページはこのように定義しています。

まずはこれを app/page.tsx に移しつつ、以下のように書き換えます。

注意点としては、以下です。

  • 全てのルーティングを一度に移行する必要はない

  • app/page.tsxpages/index.tsx は同居できない(移行時に pages/index.tsx は消さなければならない)

  • app/page.tsx のコンポーネントは async で定義し、 getStaticProps でやっていた処理をコンポーネント内に直接定義する

コンポーネントが async なのが React に慣れた人にとっては違和感かもしれませんが、 getStaticProps などが必要ないのでこちらの方がシンプルでわかりやすいですね。

これで記事一覧は表示されるようになりましたが、グローバルヘッダーは pages/_app.tsx で定義しているのでこちらも移行する必要があります。

##_document.tsx, _app.tsx を移行

App Router では pages/_app.tsxpages/_document.tsx にあたる機能を app/layout.tsx に定義する必要があります。 先ほどのトップページの移行後に npm run dev していた場合、以下のようなファイルが自動作られているはずです。(v13.4.6)

存在する場合はこの記述を参考に、なければ新しくファイルを作って app/layout.tsx を良い感じにしましょう。 この場合の注意点は下記です。

  • _app.tsx_document.tsx は全てのページの移行が完了するまで残す

  • 共通レイアウトなどで Hooks を使う場合、ファイルの先頭に "use client"; と書く(CSR の宣言)

  • CSR の場合、 export const metadata は使用できない

私の場合の完成版はこのようになりました。

##metadata を設定

さきほど export const metadata を削除したことにより、title などのメタタグが反映されなくなりました。
先述の app/page.tsx にしれっと登場していた <GlobalMeta /> では next/head でメタタグを挿入しているのですが、それが動かなくなった状態です。

既に何度かワードが出ていますが、 App Router でメタタグを反映するには export const metadataapp/page.tsx もしくは app/layout.tsx に定義してあげる必要があります。
今回は app//layout.tsx が CSR なので、 app/page.tsx ですね。
というわけで以下が最終版です。大分すっきりなりました。

動的にメタデータを表示したい場合には generateMetaData と言う名前で async function を export してあげれば良いらしいですが、それについては別途記事を書こうと思います。

##next.config.js に追記

これで npm run dev では表示的に問題なさそうです。 リリースするために next export してみましょう。

エラーになりました。

指示通り、 next.config.js に追記します。

##所感

ひとまずトップページの移行は終了です。今回は app/layout.tsx までやったので少し手間でしたが、ページ単位で移行可能なのはとても良いですね。
一方で、ページの数だけ移行作業が必要なので長く運用されているシステムなどは移行作業に多くの労力が必要になってしまいそうです。過去に Next.js を採用したサービスを思い浮かべるとやや憂鬱な気持ちになってしまいます。

"use client" や "use server" など新たに考慮すべき点が増えましたが、 getStaticProps が不要になるなど上手く整理されてきた部分もあるので早めに移行して次のアップデートに備えていきたいと思います。

© giraph.me