ハウテレビジョンブログ

『外資就活ドットコム』『Liiga』『Mond』を開発している株式会社ハウテレビジョンのブログです。

Nuxt2 → Nuxt3 アップデート最前線!最大の難関「脱 Vuex」をどのように乗り越えたか

この記事は HowTelevision Advent Calendar 2023 20日目の記事です。 昨日は SKEEME さん(id:SKEEME) の『デザインから考えるハウテレビジョンが目指す、理想の世界。』でした。

中途採用プラットフォーム Liiga のプロダクト開発チームでエンジニア&スクラムマスターをしている @59k です。

Liiga のフロントエンドには Nuxt.js を利用していますが、バージョンが 2023年12月31日 に EOL を迎える Nuxt2 であるため、現在チーム一丸となって Nuxt3 への移行プロジェクトを進めています。 Vue.js, Nuxt.js の今回のアプデは破壊的変更だらけで、苦労している方が多くいらっしゃるのではないでしょうか。(私たちもとても苦労しています)

この記事では、私たちにとって最大の壁であった「脱 Vuex」を中心に、これまでやってきたこと、よかった取り組みなどをご紹介できればと思います。

Nuxt3 へのアップデートにおいて抱えていた課題

Vuex への過剰な依存

Nuxt アップデートをするにあたって、私たちは特に 2 つの大きな課題を抱えていました。その一つが、「Vuex への過剰な依存」です。

Nuxt2 で推奨ライブラリだった Vuex が Nuxt3 では非推奨となり、代わりに Pinia が推奨となりました。Vuex を Pinia に変えるだけでもそこそこ大変だと思うのですが、私たちのチームでは「過剰に」依存していた分、さらに大きな壁になっていました。

具体的には API リクエストのための関数を Vuex の action として定義してしまっており、すべての API リクエストが Vuex に依存している状態に。その結果、実に 80 個近くの Vuex store ファイルが生まれてしまっていました。

Vuex に過剰に依存しているコードのイメージ

/* store/hoge.js */
/* 本来状態管理ライブラリに依存しなくていいコードが store 内に定義されている */

export const actions = {
  async getHoges({ rootGetters }) {
    const { data, error } = await rootGetters['fetch'](...)
    return { data, error }
  }
}

Vuetify への依存

Vue.js, Nuxt.js だけでも破壊的変更だらけなのに、Vuetify のアプデも負けないくらい破壊的変更のオンパレードです。

vuetifyjs.com

eslint-plugin-vueitfy を使って一括変更できる部分もあるものの、スタイルの上書きをしている部分などは手動で変更せざるを得ず、 これも私たちにとって大きな課題でした。

アプデのためのおおまかな戦略

これだけ破壊的変更があるとビッグバンリリースは避けられないと思いつつ、なるべくその大きさを抑えたいという背景の元、私たちは以下 2 ステップで進める戦略を立てました。

  1. Nuxt2 のまま書き換えられる部分を、main から都度ブランチを切る形で変更
    1. nuxtjs/composition-api の導入
    2. 脱 Vuex (Pinia や関数への書き換え)
    3. 環境変数の参照方法変更(process.env → composable として自作した useRuntimeConfig から参照)
  2. Nuxt3 に依存している部分を、リリースブランチから切る形で変更
    1. plugin, middleware, layout の書き換え
    2. eslint-plugin-vuetify での一括修正
    3. asyncData の書き換え
    4. v-model の書き換え

当初 Nuxt Bridge を経由する案もありましたが、「useAsyncData を含む一部の API が非対応で、二度手間・三度手間が生まれる可能性があった」「最終的に必要な工数をなるべく早く見積もりたかった」という理由で、Nuxt2 からダイレクトで Nuxt3 に移行する方針を選択しました。

最大の難関「脱 Vuex」をどう乗り越えたか

scaffold ツールを駆使しつつ、デザインパターンを使ったリアーキテクチャを実施

まず取り掛かったのが「脱 Vuex」です。事業の都合上、機能開発と並行して取り組んだという事情はありますが、80 個近くある store ファイルを全て書き換えるのに、結果的に約半年かかりました。

先述の通り Vuex に過剰に依存しており、もちろんそのまま Pinia に書き換える選択肢もあったのですが、結果的にこのタイミングでリアーキテクチャも行う意思決定をしました。状態管理ライブラリに依存しているこのアーキテクチャは、将来的にも負債となり続ける考えたためです。

具体的には Vue の API リクエスト周りのデザインパターンである「RepositoryFactory パターン」を導入し、API リクエストのためのコードが状態管理ライブラリに依存しない形で定義できるようにしました。

RepositoryFactory パターンに関する参考記事) https://tech.forstartups.com/entry/2021/07/27/194946

またこの書き換えにおいては似たようなコードを書くことが多かったため、 scaffdog という scaffold ツールを導入し、移行スピードの向上に繋げました。

「Vuex Killing Report 」というボードを作り、進捗を可視化

また、脱 Vuex を進めるにあたりもう一つ行った取り組みが、進捗の可視化です。対象ファイルが 80 個もあるということで、最初は正直絶望ムードがチーム内に漂っていました。

このムードを打破すべく、「各スプリントで 7 個ずつ書き換える」という目標を立て、その進捗がわかるボード(名付けて Vuex Killing Report)をチケット管理ツールで作成しました。

1スプリントあたりの目標ファイル数がチームにフィットしていたこと、残り store 数をいつでも確認できる状態にしたことも功を奏し、約半年間にわたる大変な書き換えを、無事目標通り終えることができました。(モチベーション維持のための仕組みは本当に大切だと実感しました…。)

このように可視化し、無事目標を上回るスピードで書き換えを完了することができました

(途中から作成した)書き換え進捗グラフ

アプデリリースに向けて最後の大詰めへ

このような工夫をしつつ、最大の壁であった「脱 Vuex」を無事乗り越えることができ、今はついに Nuxt3 としてアプリケーションを立ち上げて、書き換えを進めています。

いきなり Nuxt を 3 に変えても、そもそも画面表示にたどり着くまでに大量のエラーが出るのではないかと危惧していたのですが、pluguin だけ一旦全削除したところ、幸運にも画面表示できる状態に辿り着くことができました

asyncData の書き換えや細かいスタイルの調整などまだまだやることはありますが、Nuxt3 の最高の開発体験を手に入れるため、引き続きチームで協力して進めていきたいと思います。