Link and Motivation Developers' Blog

リンクアンドモチベーションの開発者ブログです

Vue2系からVue3系に移行しました〜!

こんにちは!リンクアンドモチベーションでフロントエンドの開発をしています。岡田(@okadaike)です。

本日は弊社プロダクトのストレッチクラウドのVueのversionを2系から3系にmigrationしたので、そのご報告になります!! 今回はプロダクトチームの中で色々と試行錯誤して進めました!ストレッチクラウドはSPAが3つあるような構成になっており、今回はそのうちの一つを移行しました!。 最後に残りの2つの移行計画もまとめようと思います!

Vue2は2023年末にEOLを迎えるのでこれからどんどん移行していくことになると思いますが誰かの役にたてればなと思います!

※余談ですが先日Vue.js v-tokyo meetup#16に参加してきました。その中で世界のアクティブVueユーザーの内6~7割はVue2を利用していると伺いました。 今年のこれからはVueのmigration祭りになりそうですね😅

背景

3つのSPAが存在していたのですが、どれもバーションは2.6.11でした。 2つのアプリケーションはcomposition APIで記述されており、もう一つはoptions APIで記述されていました。 このあと3つともmigrationしていこうと思っていたので、まずは移行のナレッジを蓄積するために最もファイル数の小さいアプリケーションに目をつけてmigrationを行っていきました。

最初に着手したアプリケーションは@vue/composition-apiのライブラリを用いてすでにcompositionAPIで記述されていたので、そこの移行はなく、シンプルにvueのversion upが目的になりました。

特に前半はいろんなPJTと並行して進めていたので、結構進みは遅かったです。最終的に2週間ぐらい時間をとって、一気に変更していきました。 あしかけ4~5ヶ月程度かかりました。

大まかな手順

  1. vue2.7系への移行
  2. build出来るように修正
  3. vue-routerの対応
  4. (関係ないけど)Viteへの移行
  5. svgファイルの修正
  6. Storeからの脱却
  7. その他細々した修正や原因調査

上記のような手順で、vue3系にmigrationしていきました〜!!

具体的な移行方法

このなかではそれぞれの手順別に意識したことや変更したポイントをかいつまんでご説明していきます

1. vue2.7系への移行

vue3にupdateする際できるだけ差分を小さくしておきたいと思いまずvue2.7系に移行しました。 もともと@vue/composition-apiを使っていましたが、その必要がなくなりvueからimportしてcompositionAPIで記述するようにしました。

各ファイルでのimportが変わったので、file changeは多かったですが、一括の置換で変更できるのでそちらで修正しました。

2. build出来るように修正

sentryやrouter, svgIconなどvueのversionに依存しそうなライブラリをコメントアウトして、vueのversionを上げてbuildしました。

- "vue": "^2.7.0", 
+ "vue": "^3.2.45", 

修正箇所は基本的にmigrationガイドを参考に修正しました。

目的を一旦buildすることにおいていたので、不必要なところはほとんどコメントアウトしました。

※移行ビルドにはvue-compatを使って移行していくフローが書かれいていますが、最終的にリリースする際にはcompatは削除してリリースしました。あまり不必要なライブラリに依存したくなかったというのもあります。

辛かったポイント

  • 何を修正していくか分からなかったので残りの修正作業工数がわからないまま修正し続けること
  • わからないところは取りあえずコメントアウト、型で怒られるところは取りあえずanyと取りあえず進んでる感じが溜まっていくところ

さて、ここまで来たら、後は動くようにアプリケーションをもとに戻していきます。

3. vue-routerの対応

vue3系ではvue-routerは4系になります。 こちらも基本的にはmigrationガイドに従って、修正していきます。 個人的に詰まったところは、

でした。

Navigation Guard周りの挙動は ルーティングを明示的に止めたい場合の処理が変更になっていたり、nextというコールバック関数が一つのガード内で一度しか呼び出せなくなったりするなど、破壊的変更があったからです。 「処理としてどうあるべきだっけ?」から考えて実装まで修正していったので、機械的に置き換えられず、結構詰まった印象があります。

query parameterを取得する箇所は 今までgetRouteParamsという関数を自作しており、自作したrouterのインスタンスからcurrentRouteのparamsを取得する処理を行っていました。 ただ、routerはvue3からsetup関数内で定義しないとエラーになるようになっており、runtimeのエラーを吐いていました。そのため、各ページのroutingを設定している箇所でpropsとして渡すように修正しました。 不要な関数もなくなりスッキリしてよかったと思っています。

// 画面名
{
  path: 'path_name',
  name: 'page_name',
  component: () => import(hogehoge),
  props: (route) => ({ queryParamId: Number(route.params.queryParamId) }),
},

4. (関係ないけど)Viteへの移行

僕たちは今までvueのbuildをするためにライブラリとしてvue-cliを使っていましたが、開発時のbuildの速度がviteの方が早いというのを聞き、このタイミングでviteに乗り換えました。

参考にした記事

具体的な修正箇所は

  • エントリーポイントの修正(ファイルの置く位置が変わります)
  • 環境変数の読み込み方法
  • 環境変数のprefix(VUE_HOGEHOGEからVITE_HOGEHOGEに変わります)

ぐらいだったと思います。 vue3だと、setupが簡単だったので、viteに移行してよかったです。hot reloadの速度が違いすぎてもうもとには戻れない体になってしまいました。 (今では他のアプリケーションの開発時に「遅いな〜...」と思ってしまいます)

5. svgファイルの修正

もともとvue-svgiconというライブラリを使用して、svgファイルを登録し、表示する というふうにしていたのですが、上手く画面に描画されないようになってしまっていました。 ライブラリには3系用のバージョンもありましたが、軽く動作確認すると使い方が良くなかったのか動作しなくなっていたので、ライブラリに依存するのをやめることにしました。

svgファイルをimportして、必要な箇所でそのコンポーネントを呼ぶように修正しました。

<template>
  <component :is="Icon[type]" />
</template>

<script setup lang="ts">
import * as Icon from './icons';
const props = defineProps<{
  type: keyof typeof Icon;
}>();
</script>

6. Storeからの脱却

このアプリケーションではpiniaを使ってグローバルな状態管理を行っていました。 しかし、piniaが上手く動いてくれませんでした。 根本的な原因はおそらくvueの2系と3系が混在するアプリケーションでpiniaの内部的なvue-demiというライブラリがSPAごとに2系と3系との振り分けをできなかったことです。(最終的にこう結論づけました) vue-demi switch 3とかを実行すると、動作確認はできるのですが、結局、全体のbuild時に上手くアプリケーションごとにバージョンを指定することができず、piniaを使わないという意思決定をしました。

今回はcomposables内でのreactiveな値はsingltonになるパターンを利用して、storeの移植を行いました。

参考にした記事

残り2つのアプリケーションの移行方法

品質の保証をすべて手で担保するのが辛いので、残りのアプリケーションの移行前にVRTを導入しました。 これもどこかでご紹介できればと思うのですが、playwright × mswの構成でBEをまるっとmockしてplaywrightでリグレッションを確認するようなテストを追加しました。 残りのアプリケーションは今回移行したもをリリースできる単位に細分化して徐々にリリースしていこうと思います。 移行の中でもどの順番でリリースしていくかを考え、細かくリリースしていきたなと思っています。 個人的には移行のタイミングでoptionsAPIを撲滅したいな〜とか考えてます。

やってよかったこと

『Vue3祭り』としてフロントエンドエンジニア数名で出社して非同期でコミュニケーションとりながらVue3化の作業のみする日を2日ほどとりました。 合宿をしてよかったなと思いました。 どうしても一人で作業しているとエラーで詰まったときなど心も詰まって辛くなることが多いですが、人に相談しながら進められるのはとても良かったです。

合宿Day1のメモ

合宿Day2のメモ

さいごに

ここに記載しきれないほどのエラーが出てきましたww

それぞれざっっっくりですが、

1. vue2.7系への移行 
  => テスト含めて3人日ぐらい
2. build出来るように修正 
  => 3hぐらい
3. vue-routerの対応 
  => Navigation Guardが詰まり、5人日とか6人日ぐらい
4. (関係ないけど)Viteへの移行 
  => 環境変数の変更、デプロイ周りの修正含めて3人日ぐらい
5. svgファイルの修正 
  => 原因調査含めて3人日ぐらい
6. Storeからの脱却
  => 原因調査含めて3人日ぐらい
7. その他細々した修正や原因調査 
  => 15人日ぐらい

多分全部で品質保証や原因調査含めて40人日ぐらいかかった気がします。 原因調査がとっても長かった気がします...

ただ、年内に3つのアプリケーションを移行するために、まずは一つ移行して知見を貯めたい。と考えやってきました。 最終的にリリースする時の差分がとても大きくなってしまったので、次回移行は切り出せるところは切り出しつつ進めていきたいと思っています。 Vue3になって出来ることも書きやすくなることも増えると思うので、Vue3についても学びを深めて行きたいと思っています!

ここまで読んでいただきありがとうございました!!