業務で Nuxt のマイナーバージョンアップを経験した際に、「良かったこと」と「反省点」があったため、この記事で振り返りたいと思います。
本記事は Nuxt v3.16.2 から v3.17.5 へのバージョンアップに関する内容です。
これから同様の作業に取り組む方の参考になれば幸いです!
- 実際に行ったこと
- 起きた問題点
- 良かったこと
- 反省点
- まとめ
今回の Nuxt バージョンアップでは、大まかに以下の手順で作業を進めました。
恥ずかしい話、2 度のリリース見送り対応を行なっています。
- Nuxt 本体と依存パッケージのリリースノートを確認
- バージョンアップ対象のバージョンで報告されている issue を確認
- 依存関係を更新し、ローカル環境および開発環境で動作確認
- 動作確認
- リリース(1回目)
- 切り戻し
- 調査(リリースノート / issue の再確認)
- 修正
- リリース前にメモリ逼迫が確認され、リリース見送り(2回目)
- 調査
- 修正
- リリース
結論から言うと、原因は Nuxt v3.17.4 以降で発生していたメモリリーク問題でした。
Nuxt v3.17.0 の大きな変更点として、 useAsyncData のキャッシュ戦略見直しがありました。
そのため、当初は自社サービス内の useAsyncData の key の見直しやキャッシュの無効化といった対応に注力してしまい、関連 issue の発見が遅れてしまいました。
今思うと視野が狭くなっていたと反省しています。
反省点の多い対応にはなりましたが、良かったこともあったのでまとめます。
NotebookLM を活用したこと
今回のバージョンアップでは、リリースノートの確認に NotebookLM を活用しました。
NotebookLM についての詳しい説明は、下記の記事がとてもわかりやすいので、ぜひご参照ください!
正直なところ、 Nuxt v3.16.2 から v3.17.5 までのリリースノートをすべて読むのは骨が折れる作業です。(結局、リリース見送り後に隅々まで読みましたが…)
そこで、ハルシネーション(AIによる誤情報の生成)を起こさず、関連情報を引用付きで出力してくれる NotebookLM を活用し、効率的にリリースノートの要点を把握しました。
「まずはリリースノートの全体像を掴みたい」「時間がないので対話形式でリリースノートを読みたい」という方にはとてもおすすめです。
Nuxt のソースコードへの理解
今回、リリースが見送りになったことで、自社サービスのコードだけでなく、 Nuxt のコンポーザブル(具体的には useAsyncData など)の内部実装まで追って調査を行いました。
当初は node_modules 内のコードを直接確認していましたが、ビルド後のファイルは読みにくいという課題がありました。(ログを仕込めるメリットはあります)
そこで、 Nuxt の公式リポジトリを参照し、ソースコードを直接調査しました。
GitHub の Web UI 上で Copilot を使ってファイルに関する質問ができるため、これも活用しながら調査を進めました。
次に、今回のバージョンアップ対応における反省点をまとめます。
依存パッケージのバージョンアップの重要性
今回は、依存パッケージのバージョンアップに関する確認観点が漏れており、リリースノートや issue のチェックも不十分でした。
今後どうすべきだったのか、改めて整理します。(もちろん、これが唯一の正解ではありません)
Nuxt のようなフレームワークをバージョンアップする際は、依存パッケージの更新も重要です。
例えば、 Vue や @nuxt/image などが挙げられます。
ただし、何も考えずに依存パッケージを最新版にすれば良いというわけではありません。
実際に今回のメモリリーク問題は、 Nuxt v3.11.2 以降と Vue v3.4.28 以降の組み合わせで発生する事象でした。
※ すべてのプロジェクトで起きるわけではなく、一部の SSR アプリケーションで発生するとのことです。
※ 2025年7月現在、根本原因が Nuxt 側か Vue 側かはまだ特定されていません。
この issue の回避策として、 Vue のバージョンを v3.4.27 に固定することで、メモリリークを抑制できました。
今回はかなり特殊なケースだと思いますが、今後は以下の観点を念頭に置きたいと思います。
- Nuxt が内部的に使用しているパッケージと互換性のあるバージョンか
- プロジェクトの package.json で指定しているバージョンが、 Nuxt の依存関係(例: node_modules/nuxt/package.json 内の Vue のバージョン)と乖離していないか
- 依存パッケージの対象バージョンで、新たな issue が報告されていないか
- Nuxt のリポジトリで関連 issue が起票されていないか
- 依存パッケージのリリースノートに、プロジェクトに影響のある破壊的変更が含まれていないか
issue のチェックをサボらない
今回の問題は、メモリリークに関する issue にさえ気づいていれば、リリース見送りを回避できた可能性が高いです。
(ただし、この問題は一部のプロジェクトでしか発生しないため、現実的には1回目のリリース見送り後にこの issue を発見できていれば、2回目の見送りを防げたと考えています)
今回の反省点は、自社プロジェクトのコードを疑うあまり、 issue の確認が疎かになったことです。
もちろん、自社のコードを疑う視点は重要ですが、
- 公式ドキュメントに沿った記述への修正
- 今回の主要アップデートであったキャッシュ機能の無効化
- 依存パッケージの更新とリリースノートの確認
- ローカル環境や少人数の開発環境では顕著な問題が発生しなかった
といった状況が揃った時点で、調査の方向性を Nuxt 本体の issue 精査や、ソースコード以外のメトリクス監視へと切り替えるべきでした。
あるいは、リリースノートと同様に issue の情報も NotebookLM にインプットするべきだったかもしれません。
最近では n8n などを活用して、特定リポジトリのリリースノートや issue を要約・通知する仕組みも作れるようなので、導入を検討する価値はありそうです。
原因調査の幅を広げる
お恥ずかしながら、メモリリークの発生を突き止めたのは、1回目のリリース見送り後に他チームのメンバーから情報共有を受けたのがきっかけでした。
CPU とメモリ使用率のスパイクは確認していましたが、メモリが解放されずに継続的に使用量が増加していくという、普段とは異なる挙動までは特定できていませんでした。
なぜ、普通なら気づく観点が漏れてしまっていたのかというとさまざまな理由があると思っています。
- 原因の切り分けが明確にできていなかった
- 現状起きている事象と、考えられる原因を冷静にリストアップし、知見のあるメンバーを早期に巻き込むべきでした
- リリースを焦り、視野が狭くなっていた
- このバージョンアップで解消される不具合が複数あったため、焦りが生じて視野狭窄に陥っていました
- ソースコードばかりを疑っていた
- 前のセクションでも触れましたが、自社のコードに問題があると思い込み、インフラのメトリクス監視や Nuxt 本体の issue 確認といった、より広い視野での調査ができていませんでした
以前、現場の先輩エンジニアに勧められた本の中に、以下の印象的な一節があります。
「普段の私なら、ログで問題を見つけたら、「ここが原因かもしれない」「いや、あそこの不具合だろうか」と試行錯誤をする場面だ。
あたりをつけて修正して、プログラムをサーバーに移動させて、動かして、またログを見る。ログは反映されるまでに15分くらいかかるから、いくつか試すのもかなり時間がかかる。
ところが、ポールがとった行動は、私と真逆のアプローチだった。彼は最初の一つのログだけを見て「仮説」を立て始めた。手は一切動かさない。」¹¹ 牛尾剛『世界一流エンジニアの思考法』文藝春秋, 2022年, 第1章「世界一流エンジニアは何が違うのだろう? – 生産性の高さの秘密『トップエンジニアの衝撃的な解決法』」
私の問題解決アプローチが試行錯誤に終始してしまい、引用した例のように「まず仮説を立て、それを証明するために行動する」という動きができていなかったと反省しています。
これができていれば、もっと迅速に問題解決できたはずです。
今回は、 Nuxt のバージョンアップ経験を通して得た学びを備忘録としてまとめました。
もちろん、今回記載した以外にも、細かい実装面での反省点や、基礎知識の不足を痛感した点もあります。
今回の経験を糧に、来る Nuxt 4 に向けて、日々開発業務に取り組んでいきたいと思います。
Views: 0