Next.js 12→13(ついでに React 17→18)へ移行する際にやったこと
前置き
1年ほどReact/Nextの技術的キャッチアップができていなかったのでバージョンアップしてリファクタリングしながら理解を深めようと思った。
React 18 で追加された主機能もまだちゃんと試せていなかったからちゃんとやる。
移行前の関連パッケージバージョン
- next@12.1.3
- react@17.0.2
- react-dom@17.0.2
移行後の関連パッケージバージョン
- next@^13.1.0
- react@^18.2.0
- react-dom@^18.2.0
やること/試すこと
- packageのバージョンアップ
- next-transpile-moduleの削除
- turbopack
- next/link の変更に対応
- コンポーネントの型修正
- app directory
- Layouts
- Cloud Run へのデプロイ
- componentのディレクトリ構成を変える
体系的に理解するために読んだ記事たち
packageのバージョンアップ
ふつうにpackage.jsonで指定のバージョンに変更して yarn isntall し直した
next-transpile-moduleの削除
yarn workspaceを用いたmonorepo構成をとっており、共通処理をcommon
というworkspaceをライブラリとして使えるようにnext-transpile-module
とnext-component-plugins
を使っていた。
このツイートを見かけて、Next.js 13 の transpilePackages
オプションを使えば不要になるということでやった。
next.config.js は以下のように変わった(一部省略している)
before
const withPlugins = require('next-compose-plugins')
const withTM = require('next-transpile-modules')(['common'])
module.exports = withPlugins([withTM], {
distDir: '.next',
sassOptions: {
includePaths: [path.join(__dirname, 'styles')],
},
swcMinify: true
})
after
const nextConfig = {
distDir: '.next',
reactStrictMode: true,
sassOptions: {
includePaths: [path.join(__dirname, 'styles')],
},
swcMinify: true,
transpilePackages: ['common'] // これだけで良くなった!
}
module.exports = nextConfig
turbopack
webpackに代わる爆速バンドラーとして話題になっていたので試してみようと思った。
結論、対応しているoptionsが少なくてproduction buildにも対応しておらず導入を見送った。
Reference
Note: Turbopack in Next.js currently only supports next dev. View the supported features. We are also working to add support for next build through Turbopack.
next/link の変更に対応
今までnext/link
からimportして使えるLinkコンポーネントはaタグを使用する必要があったが、aタグが不要になったことがBlog - Next.js 13で紹介されていた。これは地味に嬉しい。
before
<Link href="/about">
<a>About</a>
</Link>
after
<Link href="/about">
About
</Link>
毎度aタグを追加するのが面倒だったので、今までは以下のようなラッパーコンポーネントを用意していたが、不要になったので削除できた🎉
const EnhancedLink = (props) => {
const { children, className = '', pathname, query, target } = props
return (
<Link
href={{
pathname,
query,
}}
>
<a {...{ className }} target={target}>
{children}
</a>
</Link>
)
}
コンポーネントの型修正
これはNext.jsを13にしたからではなくReactを18にしたから。
React.FC
がchildren
を持たなくなったので、childrenを使いたいコンポーネントのpropsの型にchildren: ReactNode
を明示的に追加した。
app Directory
Next.js 13の目玉機能だけどまだbetaなのでproductionでは使わない。
とはいえ近々alphaになるやろと思って今のうちにキャッチアップしておく。
pages Directory を app Directory に移行
今まで file based routing を担っていた pages Directory を app Directory に変更。
app Directory 内のファイルは全て Server Component として扱われるとのこと。
出たな、Server Component。(以下、RSC)
RSCは今まで触っていなかったので各種ドキュメントを読んでみた。
最初は Server Side Rendering (SSR) との区別がつかなかったが別物だった。
Next.jsにおいて、Server Components では colocated data fetching が強みらしい。
ちなみに app Directory ではgetServerSideProps
やgetStaticProps
, getInitialProps
などの既存のデータ取得方法は使えない。
Previous Next.js data fetching methods such as getServerSideProps, getStaticProps, and getInitialProps are not supported in the new app directory.
もしそれらを使いたければ pages Directory を使う必要があるようだ。
※ app Directory と pages Directory は共存できる。
Server Components を使うと何が嬉しいのか
気力があればまとめる
Fetch API
気力があればまとめる
Layouts
ドキュメントや先人たちの記事通りに対応した。
Cloud Run へのデプロイ
Next.jsの実行環境として Cloud Run を採用しているため、影響があったら嫌だなーと思っていたけどやっぱりあった。
前提として、Dockerのマルチステージングビルドをしている。
ポート番号のエラー
ビルドは正常終了したが、container imageをdeployするときにエラーとなった。
ERROR: (gcloud.run.deploy) The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. Logs for this revision might contain more information.
デフォルトの8080番ポートに繋ごうとしているが接続できねーぞとのこと。
docker関連ファイルを見直す。
runner:
container_name: nextjs-app-multistage-runner
profiles:
- donotstart
stdin_open: true
ports:
- target: 3000
- published: 3000
+ published: 8080
protocol: tcp
-EXPOSE ${NEXTJS_APP_PORT:-3000}
+EXPOSE 3000
+ENV PORT 3000
WORKDIR /workspace/packages/app
-CMD ["yarn", "start", "-p", "${NEXTJS_APP_PORT:-3000}"]
+CMD ["yarn", "start"]
portsの指定については以下を参照した。
yarn install と build の時間が延びた
cacheが効いていない?
-> cacheだった。
初回
- yarn install: 10m 36s
- build: 5m くらい
2回目
- yarn install: 7m 29s
- build: 4m くらい