きゃべログ

Gatsbyのバージョンをv2からv5にアップデートしました

JavaScript

この記事はほぼ横浜の民 Advent Calendar 2022の2022年12月21日の記事です。

概要

2020年の12月にこのブログをGatsbyで構築して、早くも2年が経過しました。当時のGatsbyのメジャーバージョンは2で、2022年12月現在は5です。もともと億劫でバージョンアップしようと思ってませんでした。

M1 Macにブログのリポジトリをクローンしてきてサクッとビルドできると思ったら上手くいかなくて、ビルドできるようにするためにパッケージをアップデートしました。ちょっと前にやったので忘れてしまったのですが、多分なにかのモジュールがApple Siliconに対応していなかったのでこの作業をした気がします。今度はバージョンの依存関係でハマり、この際なのでGatsbyのメジャーバージョンを最新の5に上げちゃおうと決意しました。

ググってみるも、v2からv5に一気に上げている人の記事が出てこなかったので、誰かの役に立てばと思い正しいやり方なのかはわからないですが、作業メモとして残しておきます。

追記: この記事を書いた後にググってみたらちょうどタイムリーに2022年12月にv2からv5にアップデートした方の記事が出てきました。 そうだ、ライブラリをアップデートしよう。~ Gatsby v2からv5に上げてみた - Qiita

作業ログ

以下は実際にやったことをメモしています。 基本的に作業の流れはGatsby公式のMigration guideを参考にして実施しました。

まずは v2からv3に上げて、その後v4に上げて、最後にv5に上げるようにするのがおすすめと公式のMigration Guideには書いてあります。しかし最新バージョン以外にアップデートする場合にパッケージの一括アップデートをするいい方法が見つからなかったのでv2からv5に一気に上げることにします。

nodeのバージョンを18にする

Gatsby v5からnodeの最低バージョンは18になったので更新が必要です。

ローカルのnodeバージョンを変える

私はnvmでnodeのバージョン管理をしています。 18系のnodeをインストールして、それを利用するようにします。

nvm install v18.12.1
nvm use v18.12.1

CIのnodeのバージョンを18にする

私はCIでブログをビルドするマシンのnodeのバージョンを変えました。 この手順は構成によって不要かもしれないです。 ビルドからデプロイまでGithub Actionsでやっているので.github/workflows配下のyamlファイルを変更しました。

Gatsbyのバージョンを上げる

Gatsbyを最新版にしようとして npm install gatsby@latestを実行するとPeer Dependencyのエラーが出ました。 問題が出たら後で修正するとして、まずはライブラリ全般を一気に上げちゃいたいので、ひとまず--legacy-peer-depsオプションをつけて上げました。

npm install gatsby@latest --legacy-peer-deps

gatsby2.27.5 -> 5.2.0 に上がりました。

Reactのバージョンを上げる

Reactも同様にバージョンアップしました。

npm install react@latest react-dom@latest --legacy-peer-deps   

その他のパッケージのバージョンを上げる

npm outdated して一個ずつ慎重にpackage.jsonを書き換えるのが筋かもしれないですが、npm-check-updatesを使って一気にアップデートすることにしました。このためにv2->v3, v3->v4, v4->v5に段階的にアップデートするのではなく、v2->v5と一気にアップデートすることを選びました。

まずは最新にアップデートされるとバージョンがどう変わるかを確認します。

npx npm-check-updates

がっつりメジャーバージョンがあがるようです。

 @fortawesome/fontawesome-svg-core     ^1.2.32  →    ^6.2.1
 @fortawesome/free-brands-svg-icons    ^5.15.1  →    ^6.2.1
 @fortawesome/free-regular-svg-icons   ^5.15.1  →    ^6.2.1
 @fortawesome/react-fontawesome        ^0.1.13  →    ^0.2.0
 gatsby-plugin-feed                     ^2.5.7  →    ^5.2.0
 gatsby-plugin-google-analytics         ^2.3.6  →    ^5.2.0
 gatsby-plugin-manifest                ^2.4.14  →    ^5.2.0
 gatsby-plugin-offline                 ^3.2.13  →    ^6.2.0
 gatsby-plugin-react-helmet             ^3.3.6  →    ^6.2.0
 gatsby-plugin-sass                     ^2.7.0  →    ^6.2.0
 gatsby-plugin-sass-resources           ^2.0.0  →    ^3.0.1
 gatsby-plugin-sharp                   ^2.6.36  →    ^5.2.0
 gatsby-plugin-sitemap                  ^2.9.0  →    ^6.2.0
 gatsby-remark-autolink-headers         ^2.9.0  →    ^6.2.0
 gatsby-remark-copy-linked-files        ^4.2.1  →    ^6.2.0
 gatsby-remark-images                  ^3.3.14  →    ^7.2.0
 gatsby-remark-prismjs                  ^3.5.6  →    ^7.2.0
 gatsby-remark-responsive-iframe        ^2.4.7  →    ^6.2.0
 gatsby-remark-smartypants              ^2.3.6  →    ^6.2.0
 gatsby-source-blogger                  ^1.2.1  →    ^1.3.1
 gatsby-source-filesystem              ^2.3.14  →    ^5.2.0
 gatsby-transformer-remark             ^2.8.20  →    ^6.2.0
 gatsby-transformer-sharp               ^2.5.7  →    ^5.2.0
 lodash                               ^4.17.20  →  ^4.17.21
 prettier                                2.0.5  →     2.8.1
 prismjs                               ^1.20.0  →   ^1.29.0
 react-helmet                           ^5.2.1  →    ^6.1.0
 typeface-merriweather                  0.0.72  →    1.1.13
 typeface-montserrat                    0.0.75  →    1.1.13

先ほど更新した通りにpackage.jsonを更新します。 破壊的変更によるコード修正にびびりながら。

npx npm-check-updates -u

Peer Dependencyの修正

念の為、check-peer-dependenciesというパッケージを使って散々無視してきたPeer Dependenciesを確認します。

christopherthielen/check-peer-dependencies: Checks peer dependencies of the current NodeJS package. Offers solutions for any that are unmet.

npx check-peer-dependencies

実行してみたところ、いくつかPeer Dependencyの問題が発見されました。私の場合はpostcss, react, gatsby-plugin-sass-resourcesに修正が必要とのことです。 このパッケージの便利なところは次のコマンドで解決法を調べることができるところ。

npx check-peer-dependencies --findSolutions

postcssのPeer Dependency解決

postcssについては8.4.19にアップデートしたまえと提案があったので、その通りにインストールする。

npm install postcss@8.4.19

reactのPeer Dependency解決

reactについては解決法なしとのこと。 調べてみるとPeer DependencyはGatsby5.2.0が指定している"react-server-dom-webpack": "0.0.0-experimental-c8b778b7f-20220825"の依存関係の中で、react@0.0.0-experimental-c8b778b7f-20220825を指定しているため生じている。experimentalというくらいだからまあいいかということで一旦無視しておくことに。

gatsby-plugin-sass-resourcesのPeer Dependency解決

元々インストールしていた、gatsby-plugin-sass-resourcesのgatsbyのバージョン指定が^4.0.0で、gatsby5系には対応していませんでした。このプラグインは各scssファイルから、プロジェクト全体で使用する共通のスタイルや関数を記述したglobal.scssを読み込むために使っています。

このプラグインのGitHub Issueを見てみると、v3, v4の時のも同様の問題があったようで、v4のアップデートまではPull Requestが上がって対応されています。さらに実装を見てみると、gatsby-node.jsonCreateWebpackConfigsass-resources-loaderのセットアップをするというかなりシンプルなものでした。今後バージョンを上げるときにプラグインのアップデートでつまずくのはつらいので、gatsby-plugin-sass-resourcesのライセンスがMITなのを確認し、自分のブログの実装に取り込ませてもらうことにしました。

まずはsass-resources-loaderをインストールします。

npm install sass-resources-loader

そしてgatsby-node.jsに次のコードを追加します。 詳しいオプションの設定方法はsass-resources-loaderのREADMEを読んでください。

exports.onCreateWebpackConfig = ({ actions }) => {
  actions.setWebpackConfig({
    module: {
      rules: [
        {
          test: /\.s[ac]ss$/,
          loader: "sass-resources-loader",
          options: {
            resources: ['./src/components/global.scss']
          }
        }
      ]
    }
  });
};

パッケージをインストールする

最後にパッケージをインストールします。

npm install

問題なくインストールできたので、前述のreactのexperimentalバージョンのPeer Dependencyのことは忘れることにしました。

Breaking Changesに対応する

パッケージのインストールが完了したので、あとは地道に破壊的変更に対応していきます。 まずは開発サーバーが立ち上がるかどうかを確認します。

gatsby develop

すんなりいくはずもなく、エラーがでました。いくつか修正が必要そう。

sass-loaderの修正

gatsby-plugin-sassプラグインを2.7.0から6.2.0にアップデートしたため、sass-loader周りでエラーが起きていました。

  ModuleBuildError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
  ValidationError: Invalid options object. Sass Loader has been initialized using an options object that does not match the API schema.
   - options has an unknown property 'indentedSyntax'. These properties are valid:
     object { implementation?, sassOptions?, additionalData?, sourceMap?, webpackImporter? }

対処法: SASSからSCSSに乗り換え

結論から言うとSASS記法からSCSS記法に乗り換えることにしました。ちゃんとやればSASS記法のまま動くようにできるのかもしれないのですが、3時間近く格闘しても上手くいかなかったので、諦めてSASS記法からSCSSに移行することを決めました。SCSSの方がPure CSSからの移行性が高いこと、SCSSの方が情報ソースが多いこともあり、やぶさかではないです。

SASS記法とSCSS記法についてはこちらを参照。 Sass: Syntax

手動で SASS->SCSS の変換をするのが面倒すぎるので、rubyのsassというgemをインストールするとバンドルされているsass-convertというコマンドを使って変換することにしました。ちなみに、ruby sass自体deprecatedなのでいつまで使えるかはわからないです。

GitHub sass/ruby-sass#sass-convert

次のように、リポジトリ内のSASSファイルを一括でSCSSに変換します。

find . -type f -name "*.sass" | xargs -I {} sh -c 'sass-convert {} $(dirname {})/$(basename {} .sass).scss'

これでsass拡張子を持つファイルをすべてscssに変換することができたので、各参照元の拡張子も変更していきます。 この作業が完了するとビルドはひとまず完了するようになりました。

(参考) SCSS記法に乗り換える前に試したこと

先述のとおり、ビルド時エラーはSASS記法からSCSS記法に変更することで解決したのですが、そこに至るまでに色々試したので記録として残しておきます。

再掲しますが、最初に出力されていたエラーはこちらです。

  ModuleBuildError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
  ValidationError: Invalid options object. Sass Loader has been initialized using an options object that does not match the API schema.
   - options has an unknown property 'indentedSyntax'. These properties are valid:
     object { implementation?, sassOptions?, additionalData?, sourceMap?, webpackImporter? }

もともとSASS記法で書いているため、gatsby-config.jsgatsby-plugin-sassのオプションとして次のような設定をしていました。indentedSyntaxというのはいわゆるSASS記法のことです。

    { 
      resolve: "gatsby-plugin-sass",
      options: {
        indentedSyntax: true,
      }
    },

しかしgatsby-plugin-sassのv3.0.0アップデートのBreaking changesの中に、sass-loaderのオプションはsassOptionsオブジェクトに入れて渡すような仕様変更が入っています。

そのため次のように書き換えました。

    { 
      resolve: "gatsby-plugin-sass",
      options: {
        sassOptions: {
          indentedSyntax: true,
        },
      },
    },

最初に出ていたエラーは出なくなりました。ここまではドキュメントも整備されていたので割とすんなり。 次はSyntax Errorのエラーメッセージが出てきました。内容はどうもSASSファイルがSCSSファイルとして解釈されているようです。オプションにindentedSyntax: trueが設定されているのにも関わらずこのエラーが出るのは不思議でした。 その後SASSファイルを検出するための正規表現の設定を変更してみたりしましたが、上手くいかず、見切りをつけてSASS記法からSCSS記法に乗り換えることにしたのでした。

GraphQLのクエリの修正

ここまでですでにビルドは完了しており、Errorレベルの問題の対処は完了しました。 ここからはWarnレベルの問題を修正していきます。

こんな感じのWarnが目につきました。その後に大量のクエリの出力が。

warn Deprecated syntax of sort and/or aggregation field arguments were found in your query (see https://gatsby.dev/graphql-nested-sort-and-aggregate). Query was automatically converted to a
new syntax. You should update query in your code.

これはv4 -> v5のBreaking Changeに含まれる、GraphQLのスキーマ変更によるものです。クエリ中のsortfieldの引数の書き方が変わるので修正してくださいという内容です。 Migrating from v4 to v5#GraphQL schema: Changes to sort and aggregation fields

Warnメッセージの中には丁寧に修正方法の提案までしてくれるのですが、もっと簡単に修正する方法があります。 Gatsbyが公式で用意してくれているgatsby-codemodsというスクリプトがあるのでこちらを活用します。

npx gatsby-codemods@latest sort-and-aggr-graphql .

指摘されていた修正が適用され、ついでにクエリのフォーマットもされます。 gatsby developを実行して動作確認してWarnが出なくなること、動作に問題がないことを確認しましょう。 実行後、修正すべきクエリが変更されるのでコミットして完了です。

react-helmetからGatsby Head APIへの移行

gatsby@4.19.0にGatsby Head APIというものが実装されました。これによりHeadタグの中に任意の要素を追加できるようになります。一方でreact-helmetは非推奨になるらしいです。

warn gatsby-plugin-react-helmet: Gatsby now has built-in support for modifying the document head. Learn more at https://gatsby.dev/gatsby-head

詳しく記載があるページを見つけたので実際の手順は割愛しますが、この辺を参考に実施すると良いと思います。

gatsby-imageからgatsby-plugin-imageへの移行

gatsby-imageについてもパッケージを移行してくれというWarningが出ているので対応します。

warn [gatsby-transformer-sharp] The "fixed" and "fluid" resolvers are now deprecated. Switch to "gatsby-plugin-image" for better performance and a simpler API. See https://gatsby.dev/migrate-images to learn how.

詳しいマイグレーション手順は公式の記事に掲載されています。「How to Migrate」のセクションを読みましょう。 簡単に脱gatsby-imageパッケージできるはずです。

Migrating from gatsby-image to gatsby-plugin-image | Gatsby

まとめ

Gatsbyのバージョンを2から5まで一気にアップデートしてみました。リリースノートを全部読み込んですべて対処したわけではなく大雑把に対応しましたが、今のところ大きな問題はなさそうです。目に見えてわかる変化は諸々のAPIが変わったことと、gatsby develop実行時のWarningがなくなったことくらいですが、すっきりしました。新年を清々しく迎えられそうです。みなさんも年末の大掃除として、パッケージのバージョンアップはいかがでしょうか。良いお年を。


きゃべ (@cab_kyabe)
きゃべ (@cab_kyabe)
Software Engineer / Product Manager