chocolat

tips_nextjs

GatsbyJS から Next.js へ移行

August 29, 2022

勉強をかねてGatsbyから同じReact.jsベースで開発されたJavaScriptフレームワークの Next.js へ移行しました。

パフォーマンスの観点ではGatsbyのほうが良いという記事をいくつか読みましたが、移行を決めた理由は主に次の3つです。

  • 更新の度にNetlify上でのデプロイのエラーが頻発
  • GatsbyJSは便利なプラグインを多く利用できる反面、依存関係の脆弱性の問題がある
  • Next.js と TypeScript でサイトを構築してみたかった

Next.jsについて

Next.jsはReactベースで開発されたJavaScriptフレームワークです。

Next.js gives you the best developer experience with all the features you need for production: hybrid static & server rendering, TypeScript support, smart bundling, route pre-fetching, and more. No config needed.

環境について

移行前 移行後
フレームワーク GatsbyJS Next.js
言語 React TypeScript
ホスティングサービス Netlify Vercel

移行作業

サイトの構成などによって必要な移行作業は変わりますが、まずは Next.js の公式サイトで公開されている「Migrating from Gatsby」ページの作業を行います。

当サイトで上記のページの手順以外に必要になった作業は主に次の4つです。

  • 各記事のパーマネントリンクおよびディレクトリ構成を維持する
  • 記事内の画像の読み込み
  • 記事内のマークダウンにシンタックスハイライトを適用する
  • 目次(Table of Contents)の表示
  • カテゴリー、タグ一覧ページの作成
  • Google Analytics, Google Adsens などの設定
  • Netlify から Vercel への変更

各記事のパーマネントリンクおよびディレクトリ構成を維持する

CMSは未導入のため各記事のデータは src 内の markdown ファイルを読み込んでいます。
Gatsbyでサイトを作成した際に他のサイトを参考にしながら以下のようなルールを決めてファイル管理を行っていました。

  • 記事のファイルも投稿日順で管理できるようにするためファイル名を「 日付-スラッグ.md 」とする
  • ただし、パーマネントリンクはスラッグのみ
  • 記事内に画像がある場合は 日付-スラッグ というフォルダを作成し、その中に index.md を作成する
  • about, policy などのページもマークダウンで管理する
src
├──contents
│   ├── pagegs
│   │   ├── about.md
│   │   └── policy.md
│   │
│   ├── posts
│   │   ├── blog
│   │   │    └── 日付-スラッグ.md
│   │   └── tips
│   │   │    ├── 日付-スラッグ.md
│   │   │    └── 日付-スラッグ
│   │   │          ├── index.md
│   │   │          └── image.jpg

上記を Next.js 移行後も維持したかったので、「Migrating from Gatsby」の「Data Fetching」の項目の getPostBySlug にあたる部分でディレクトリ構造にあわせた修正が必要でした。

記事内の画像の読み込み

Next.js では静的ファイルは public フォルダで管理します。

当サイトでは、記事内の画像は記事の markdown ファイルと同じフォルダ内で管理しています。そうすることで記事内の画像の読み込みは以下のパスを書くだけで読み込むことができていました。

![](./image.jpg)

方法を探る中で next-optimized-images ライブラリや loader を使用した方法などいくつか試しましたが上手く読み込めなかったため、正しいかどうかはわかりませんが、最終的に次の方法で、パスの書き換えなどをせずに記事内の画像が読み込まれるようにできました。

  1. copy-webpack-plugin をインストール

  2. next.config.js で記事内の画像データをビルド後に静的ファイルが置かれる .next/static/media/ にコピーする。

/** next.config.js */
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
  webpack: (config) => {
    config.plugins.push(
      new CopyWebpackPlugin({
        patterns: [
          {
            from: './src/contents/posts/**/**/*', // コピー元のファイルを指定
            to: './static/media/img/[path][name][ext]', // コピー先のフォルダを指定
            globOptions: {
              ignore: ['./**/*.md'], // 記事の markdown ファイルは除外
            }
          },
        ]
      })
    )
    return config
  }
}

Webpack プラグインの使用やカスタマイズについては、Next.js 公式サイトの「Custom Webpack Config」に説明がありますが、

Note: changes to webpack config are not covered by semver so proceed at your own risk

という注意書きがありますので、ご使用はご自身の判断になります。

記事内のマークダウンにシンタックスハイライトを適用する

Gatsby では gatsby-remark-prismjs プラグインをインストールして使用していたので、Next.js でも同じ Prism.js を使用することにしました。

markdown への適用は、 markdown ファイルの変換方法によって変わりますが、おおまかな導入の流れとしては次の手順になります。

  1. Gatsby用のプラグインの代わりに prismjsbabel-plugin-prismjs をインストール

  2. _app.tsxprism.css と使用したいテーマのCSSファイルを読み込む

/** _app.tsx */
import '@(パス)/prism.css'
import '@(パス)/prism-tomorrow.css'
  1. 記事コンポーネントで Prism.js を markdown に適用させる

  2. Babel の設定ファイル .babelrc に使用言語やオプション等を記述する

/** .babelrc */
{
  "plugins": [
    "@emotion/babel-plugin",
    [
      "prismjs",
      {
        "languages": [
          "javascript", 
          "typescript",
          "jsx",
          "css",
          "markup",
          "json",
        ],
        "plugins": ["show-language"], // 言語名のラベルを表示
        "css": true
      }
    ]
  ]
}

目次(Table of Contents)の表示

Gatsby では gatsby-transformer-remark プラグインを使用して GraphQL で目次を取得していました。

Next.js への移行にあたり、 markdown の変換に使用しているnpmパッケージ marked で目次を取得して表示させるようにしました。
'marked` を使用したTable of Contents の作成方法の詳細は別記事としてまとめる予定です。

Netlify から Vercel への変更

Next.js へ移行するにあたり、デプロイ先もNext.js を開発している Vercel 社が提供するホスティングサービスに変更するほうが都合が良さそうだったため、あわせて変更しました。

Netlify へのデプロイはGitHubのリポジトリと連携させていたため、Vercelへの移行はとても簡単にできました。

デプロイ先の変更のほかに当サイトは独自ドメインを設定しているため、以下の手順でドメインの設定変更を行いました。

  1. Netlify で独自ドメインの登録を削除する
  2. Vercel でデプロイ後に独自ドメインを登録する
  3. ドメイン契約会社の管理画面でネームサーバーの設定を変更する

追加した主なパッケージ

  • next
  • gray-matter : markdown ファイルのfront-matter解析
  • marked : markdown 変換
  • prismjs : シンタックスハイライト

最後に

Lighthouseで移行前と移行後に計測した結果です。
事前に記事で読んでいた通り、パフォーマンスはGatsbyよりも数値が下がりましたが、これから改善していこうと思います。 (Accessibility の数値が少し上がっているのは背景と文字色のコントラストを少し変更したので、Next.jsへの移行によるものではありません。)

移行前

移行後

Reference 参照