Next.js 12 からの脱却! Next.js 13 へスムーズに移行するためのアップデートガイド


こんにちは、Gaji-Labo フロントエンドエンジニアのたにもとです。

先日 Next.js 12 だった開発環境を Next.js 13 へアップデートする機会がありました。
本記事ではアップデートで対応した内容とハマった時の対処方法を紹介します!

今回対応した変更

Next.js 12 から Next.js 13 へのアップデートで対応したのは以下の3点です。

  • next/image に置き換え
  • next/link の仕様変更に伴う <Link> 構造の変更
  • SWC への移行(コンパイラの見直し)

SWC への移行は、必須ではないと考えています。

一方で Next.js 12 以降のバージョンではデフォルトで有効になっています。
可能であれば乗り換えておいた方が良いと判断し、Next.js 13 へのアップデートのこのタイミングで対応しました。

公式ドキュメントにアップデート内容の要約があるので合わせてご確認ください!

具体的な変更内容

next/image に置き換え

Next.js 13 から import 名が next/image に変更されるので置き換えます。
今回のプロジェクトでは、next/future/image が利用されていたので next/image に置き換えました。

アップデート前に next/image を利用している場合は以下の2パターンの対応方法があります。
状況に応じて対応方法を検討してください。

  • Next.js 12 と同じ仕様で利用し続けたい場合は next/legacy/image に置き換える
  • Next.js 13 の新しい仕様で利用したい場合は変更せず next/image を利用し続ける

codemod が用意されているので一度実行してみるのも良いと思います。
実行箇所のパス ./src は環境に合わせて変更し、ご利用ください。

npx @next/codemod@latest next-image-to-legacy-image ./src

import 名の置き換え以外にも、alt が必須になるなどの変更があります。
公式ドキュメントをご確認いただきながら対応されることをオススメします!

next/link の仕様変更に伴う <Link> 構造の変更

Next.js 13 では <Link> タグの中に <a> タグが内包されているとエラーになります。

// Next.js 12 の場合
<Link href="/hoge">
  <a target="_blank">リンクテキスト</a>
</Link>

// Next.js 13 の場合
<Link href="/hoge" target="_blank">
  リンクテキスト
</Link>

対応は a タグを削除するだけです。
ただ、構造に依存したスタイルが適用されていたり、 <Link> でラップした子要素に a タグが含まれていたり構造を変更するのが困難な場合もあります。
そんな場合の一時的な回避策を2つ紹介します。

  • <Link> の子要素として <a> を使わずに、直接 div や span で囲む
  • legacyBehavior を設定して対応

legacyBehavior について補足しておきます。
<Link> タグに legacyBehavior を付与することで従来の構造でリンクを機能させることができます。

<Link href="/hoge" legacyBehavior>
  <a target="_blank">リンクテキスト</a>
</Link>

Next.js 13 の仕様に沿って変更できるのがベストですが、状況に応じて利用を検討してみてください。

こちらも codemod が用意されているのでご利用いただくのも良いと思います。
実行箇所のパス ./src は環境に合わせて変更し、ご利用ください。

npx @next/codemod@latest new-link ./src

SWC への移行

SWC への移行には next.config を編集します。
今回の環境では元々 babel を利用していたのでパッケージも含めて見直しました。

この時 .babelrc などの babel に関する設定ファイルを削除しておいてください。
詳しくは後述させていただきます。

以下は削除したパッケージと追加したパッケージです。

// 削除したパッケージ
"@emotion/babel-plugin"
"babel-loader"
"babel-plugin-inline-react-svg"

// 追加したパッケージ
"@svgr/webpack"

次に next.config を修正していきます。
基本的にはこれまで使っていた記述を使うことができますが、以前は babel で行っていた Emotion の処理や SVG の処理を next.config に設定を追加しコンパイルされるように修正します。

const nextConfig = {
  swcMinify: true,
  },
  // emotion の処理を追記
  compiler: {
    emotion: true,
  },
  webpack: (config) => {
    // svg の処理を追記
    config.module.rules.push({
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    })
    return config
  },
}

アップデート時にハマったトラップと対処法

解決までに時間がかかったことを2点紹介します。

  • SWC で設定した内容がコンパイルに反映されない
  • SVG の表示が崩れる

SWC で設定した内容がコンパイルに反映されない

前述で .babelrc を削除してくださいと書かせていただいた箇所の詳細を説明します。
Next.js は .babelrc が残っていると babel の設定が優先する仕様があります。
この仕様を知らず解決までの時間がかかりました…。
なので SWC に移行する時は .babelrc を削除しましょう。

SVG の表示が崩れる

アップデート後に SVG が正しく表示されなくなるケースがあります。
これは、コンパイル時の処理が影響している可能性があります。

今回のアップデート対応のパターンだと @svgr/webpack の内部で利用されている SVG を最適化しする svgo が原因であることが考えられます。

SVG が最適化される過程で viewBox の値が削除されてしまうことで発生するようです。
これを回避するために viewBox の値が消えないように設定を追加する必要があります。

const nextConfig = {
  webpack: (config) => {
    config.module.rules.push({
      test: /\.svg$/,
      // ここを修正
      use: [{ loader: '@svgr/webpack', options: { dimensions: false } }],
    })
    return config
  },
}

Next.js 13 へのアップデートをスムーズに進めるために

メジャーバージョンのアップデートには様々なトラップがあります。
ただ、必ず誰かが困って調べた痕跡があり、解決方法が用意されていることが多いので Github の issue を中心に調べてみることをオススメします!

一時的に回避策を実行し、次のアップデートの際に対応する方が効率が良い可能性もあります。
あえて後回しにするのもスムーズにアップデートを進めるためにコツだと考えます。

Gaji-Laboでは、 Next.js 経験が豊富なフロントエンドエンジニアを募集しています

弊社では Next.js の知見で事業作りに貢献したいフロントエンドエンジニアを募集しています。大きな制作会社や事業会社とはひと味もふた味も違う Gaji-Labo を味わいに来ませんか?

Next.js の設計・実装を得意とするフロントエンドエンジニア募集要項

もちろん、一緒にお仕事をしてくださるパートナーさんも随時募集中です。まずはお気軽に声をかけてください。お仕事お問い合わせや採用への応募、共に大歓迎です!

求人応募してみる!

この記事がアップデートするために手がかりになると幸いです!


投稿者

フロントエンドエンジニア。 事業会社で LPO や EFO のサービス改善を経験し、Gaji-Labo に入社。 関わってくださる人により良い選択を提供できることを目指し日々奮闘しています。 3度の飯よりアニメが好き。