【Gatsby】v4系からv5系にアップデート

【Gatsby】v4系からv5系にアップデート

はじめに

やらねばと思いつつ先延ばしにしていましたが、ビルド時にプラグインや何やら警告が多数表示されたこともあり、今後のことも考えて Gatsby のバージョンとその他依存関係にあるプラグインもバージョンアップしました。

今回の記事はその際の記録です。

このブログを作成する経緯や機能などは以下の記事でまとめています。

開発環境

  • VS Code
  • Devcontainer
    • node image: node:18.16.1-alpine3.18
    • reverse proxy image: jwilder/nginx-proxy:alpine
    • Package Manager: yarn v1.22.19

作業ログ

以下に実施したことを記述していきます。公式の Migrating from v4 to v5 をざっと眺めましたが英文を逐一翻訳して確認していく暇は有りません。

とりあえずビルド時に発生している警告を、VS Code にインストールされているPhindにぶち込んで助言を貰います。(※Phind は有料会員です)

ざっと確認した公式に記述されている内容と、大きく異なる内容が出力されれば立ち止まって詳細を確認することとします。

ビルド時の警告

gatsby developを実行した時の警告を確認します。

warn Plugin gatsby-plugin-canonical-urls is not compatible with your gatsby version 4.17.1 - It requires gatsby@^5.0.0-next
Initializing gatsby-remark-component
warn Plugin gatsby-remark-images-zoom is not compatible with your gatsby version 4.17.1 - It requires gatsby@^2.0.0
warn Plugin gatsby-plugin-robots-txt is not compatible with your gatsby version 4.17.1 - It requires gatsby@^5.0.0
warn Plugin gatsby-remark-images-zoom is not compatible with your gatsby version 4.17.1 - It requires gatsby@^2.0.0
warn Plugin gatsby-plugin-canonical-urls is not compatible with your gatsby version 4.17.1 - It requires gatsby@^5.0.0-next
warn Plugin gatsby-remark-images-zoom is not compatible with your gatsby version 4.17.1 - It requires gatsby@^2.0.0
warn Plugin gatsby-plugin-robots-txt is not compatible with your gatsby version 4.17.1 - It requires gatsby@^5.0.0

上記のプラグインは現在のバージョンと互換性が無いようです。

gatsby-remark-images-zoomが求めているバージョンが 2 系なのは一旦無視しておきます。このプラグインは、Markdown で記載された記事内の画像にズーム機能を追加するためのプラグインです。

現在のバージョンの確認

一旦 node.js や gatsby, gatsby-cli のバージョンを確認します。

$ node -v
v18.16.1

$ gatsby -v
Gatsby CLI version: 5.13.3
Gatsby version: 4.17.1

Gatsby のアップデート

以下のコマンドを実行します。

$ yarn add gatsby@latest

# 更新されたか確認
$ gatsby -v
Gatsby CLI version: 5.13.3
Gatsby version: 5.13.7 # ◀

# package.json も変更されていた
# "gatsby": "^5.13.7",

gatsby 関連のプラグインをアップデート

今回警告が表示されているのはgatsby-*関連のプラグインでした。

package.json内をまとめてアップデートすると、動作しなかった場合に無いが原因なのか特定し辛いので、一旦これらのプラグインだけアップデートして様子を動作するか確認します。

$ yarn add gatsby-plugin-canonical-urls@latest \
           gatsby-plugin-feed@latest \
           gatsby-plugin-gatsby-cloud@latest \
           gatsby-plugin-google-analytics@latest \
           gatsby-plugin-google-gtag@latest \
           gatsby-plugin-image@latest \
           gatsby-plugin-manifest@latest \
           gatsby-plugin-offline@latest \
           gatsby-plugin-react-helmet@latest \
           gatsby-plugin-sass@latest \
           gatsby-plugin-sharp@latest \
           gatsby-plugin-sitemap@latest \
           gatsby-plugin-styled-components@latest \
           gatsby-remark-autolink-headers@latest \
           gatsby-remark-copy-linked-files@latest \
           gatsby-remark-images@latest \
           gatsby-remark-prismjs@latest \
           gatsby-remark-responsive-iframe@latest \
           gatsby-remark-smartypants@latest \
           gatsby-source-filesystem@latest \
           gatsby-transformer-remark@latest \
           gatsby-transformer-sharp@latest \
           gatsby-plugin-disqus@latest \
           gatsby-plugin-robots-txt@latest

特に問題なくアップデートされました。package.jsonのバージョンの記述も変わっています。

公式にはその他reactreact-domlatest versionにするように記述があったのでそれも実施します。

$ yarn add react@latest react-dom@latest

キャッシュの削除

アップデートは成功しましたが、過去バージョンのキャッシュが残っている可能性がるので一旦削除します。

# パッケージマネージャー関連のグローバルのキャッシュを削除
$ yarn cache clean

# .cache ディレクトリと public ディレクトリを削除
$ gatsby clean

# インストールされていたパッケージを全て削除
$ rm -rf node_modules

# 再度パッケージをインストール
$ yarn install

一旦ビルドして正常に起動する確認します。

$ yarn run local:dev

# "local:dev": "GATSBY_ACTIVE_ENV=development gatsby develop -H 0.0.0.0"
# ↑package.json の scripts 内のコマンド

正常に起動したことが確認できました。

不要なパッケージを削除

gatsby-remark-images-zoomが現在の Gatsby のバージョンに対応してないので削除すると共に、代替のプラグインが無いか探しました。

gatsby-remark-images-medium-zoom-plugin というプラグインが同等の機能を持っているようなので乗り換えます。

$ yarn remove gatsby-remark-images-zoom

$ gatsby-remark-images-medium-zoom

gatsby-config.jsも修正します。

"gatsby-config.js"
// 省略
{
    resolve: `gatsby-transformer-remark`,
    options: {
    plugins: [

        // 省略

        {
            resolve: `gatsby-remark-images`,
            options: {
                maxWidth: 1200,
+               linkImagesToOriginal: false
            },
        },
+       {
+           // 画像をクリックしたときにズームさせるプラグイン
+           resolve: `gatsby-remark-images-medium-zoom`,
+           options: {
+             // オーバーレイの色
+             background: `#000`,
+           }
+       },
-       `gatsby-remark-images-zoom`,

        // 省略

            `gatsby-remark-prismjs`,
            `gatsby-remark-copy-linked-files`,
            `gatsby-remark-smartypants`,
        ],
    },
},

実行すると、背景色も変わっており想定通りの動作をしていました。

gatsby-remark-images-medium-zoom.gif

Gatsby Head API に対応させる(2024 年 10 月 26 日修正)

Gatsby のアップデートをしていると、gatsby-plugin-react-helmetが非推奨となっている情報を見つけました。

gatsby-plugin-react-helmetは Gatsby でreact-helmetを使用するためのプラグインで、react-helmetは React コンポーネントでhead要素を制御するためのライブラリです。

gatsby-plugin-react-helmetの代わりとしてGatsby 4.19.0からGatsby Head APIという機能が追加されました。

これはreact-helmetに代わるheadタグに情報を追加できる API です。

公式ドキュメント非推奨になる react-helmet から Gatsby Head API に書き換える方法を参考にheadタグを記述していたコンポーネントを Gatsby Head API に対応させました。

修正した箇所を記録として残しておきます。

事前準備

まず不要になったプラグインと設定を削除します。

$ yarn remove gatsby-plugin-react-helmet react-helmet
"gatsby-config.js"
module.exports = {
    siteMetadata: {
        // 省略
    },
    plugins: [

        // 省略

-       `gatsby-plugin-react-helmet`,
        `gatsby-plugin-sass`,
        {
            // 省略
        },
    ],
};

Seo コンポーネントの修正

このブログではheadタグ内の記述をコンポーネント化していたので書き換えます。

"src/components/seo.jsx"
// ★react-helmet のインポートを削除
// import { Helmet } from 'react-helmet';

// ★lang を削除
const Seo = ({ description, /*lang*/, meta, title, img, location, type, date, modified }) => {

  // 省略
  /*
  return (
    <Helmet
      htmlAttributes={{
        lang,
      }}
      title={title}
      // 下層ページ(トップページでなければ)サイト名を付与する
      titleTemplate={!isRootPath ? `%s | ${defaultTitle}` : null}
      meta={[
        {
          name: `description`,
          content: metaDescription,
        },
        {
          name: `thumbnail`,
          content: imgPath,
        },
        {
          property: `og:title`,
          content: title,
        },
        {
          property: `og:description`,
          content: metaDescription,
        },
        {
          property: `og:type`,
          // og:typeをトップページ以外を判定してwebpageを出力
          content: `${isRootPath ? 'website' : 'webpage'}`,
        },
        {
          property: `og:url`,
          content: blogUrl, // ここをページURLに変更
        },
        {
          property: `og:image`,
          content: imgPath, // 画像URLを設定
        },
        {
          name: `twitter:card`,
          content: `summary_large_image`,
        },
        {
          name: `twitter:creator`,
          content: site.siteMetadata?.social?.twitter || ``,
        },
        {
          name: `twitter:title`,
          content: title,
        },
        {
          name: `twitter:description`,
          content: metaDescription,
        },
        {
          property: `twitter:image`,
          content: imgPath,
        },
      ].concat(meta)}
    ></Helmet>
  );
  */

  return (
    // React Fragmentに書き換え
    <>
      <title>{!isRootPath ? `${title} | ${defaultTitle}` : title}</title>
      <meta
        name="description"
        content={metaDescription}
      />
      <meta
        name="thumbnail"
        content={imgPath}
      />
      <meta
        property="og:title"
        content={title}
      />
      <meta
        property="og:description"
        content={metaDescription}
      />
      <meta
        property="og:type"
        content={isRootPath ? 'website' : 'webpage'}
      />
      <meta
        property="og:url"
        content={blogUrl}
      />
      <meta
        property="og:image"
        content={imgPath}
      />
      <meta
        name="twitter:card"
        content="summary_large_image"
      />
      <meta
        name="twitter:creator"
        content={site.siteMetadata?.social?.twitter || ``}
      />
      <meta
        name="twitter:title"
        content={title}
      />
      <meta
        name="twitter:description"
        content={metaDescription}
      />
      <meta
        property="twitter:image"
        content={imgPath}
      />
    </>
  );
};

Seo.defaultProps = {
    // lang: `ja`, // ★削除
    meta: [],
    description: ``,
};

Seo.propTypes = {
    description: PropTypes.string,
    // lang: PropTypes.string, // ★削除
    meta: PropTypes.arrayOf(PropTypes.object),
    title: PropTypes.string.isRequired,
};

export default Seo;

Gatsby Head API ではheadタグ内しか書き換えれないので、html ファイルビルド時にhtmlタグにlang属性を指定できるようにプロジェクトディレクトリ直下にgatsby-ssr.jsというファイルを作成して以下のように記述します。

"gatsby-ssr.js"
exports.onRenderBody = ({ setHtmlAttributes }) => {
  setHtmlAttributes({ lang: 'ja' });
};

onRenderBodyメソッドは、ビルドプロセスで実行され生成される静的な HTML ファイルをカスタマイズすることができます。

各コンポーネントの修正

次にSeoコンポーネントを使用していたページを修正します。

"index.jsx"

// 省略

const BlogIndex = ({ pageContext, data, location }) => {
  const sidebarTags = pageContext.tags.sort();
  const siteTitle = data.site.siteMetadata?.title || `Title`;
  const { nodes } = data.allMarkdownRemark;
  const { current, totalPageNumber } = pageContext;

  return (
    <Layout
      location={location}
      title={siteTitle}
    >

    // 以前読み混んでいた箇所を削除
    // <Seo location={location} title={siteTitle}>

    </Layout>
  );
};

export default BlogIndex;

// ↓新たに追加
export const Head = ({ data, location }) => {
  const siteTitle = data.site.siteMetadata?.title || `Title`;

  // Head 関数内でSeoコンポーネントを返す
  return (
    <Seo
      title={siteTitle}
      location={location}
    />
  );
};

これらの修正を各ページで実施します。

修正後、ogpなど各metaタグが正常に出力されていることを確認します。

最後に

今回はgatsby-*関連のプラグインのみアップデートしました。

v4 系 → v5 系のアップデートに関する修正があれば随時更新しようと思います。