こんにちは、LAPRASの業務委託エンジニアのしんです。
先日弊社のプロダクト(LAPRAS と LAPRAS SCOUT)のVue3アップデートがついに完了しました🎉
中〜大規模プロダクトのVue3移行を(開発を止めずに)2回行ったことで様々な学びがありましたので、連載記事の形でVue3移行について解説していきたいと思います。
移行ビルドを用いたVue3移行は大まかに、
- 移行ビルドの導入前の準備
- 移行ビルドの導入 & 削除
のフェーズに分けることができます。
第1回目の本記事ではまず「移行ビルド導入前の準備」についてまとめていきます!
移行ビルド導入前にしたほうがいいこと
一度移行ビルドを入れてしまうと、完全に動く状態になるまでmain
ブランチへマージできません。
移行ビルド導入のPRは非常に巨大になり工数もかかるため、導入前にできる作業は全て先にやっておくのが吉です(参考までに、300コンポーネント規模のプロダクトの移行ビルド導入は、メイン作業者1人で2ヶ月ほど掛かりました)。
① Vue2.7へ移行しておく
Vue2.6でも移行ビルドを導入できますが、一旦Vue2.7に上げたほうがやはり無難だと思います。Vue2.7移行を挟むメリットとしては、
- Vue2.7移行とVue3移行で重複する作業があるので、Vue3移行のPRを小さくできる
- バグの原因究明を行う際にVue2.7移行の情報は探さなくてもよくなるなど、問題の切り分けができる
などが挙げられます。
ただそのぶん工数が増える可能性はあるので、そこはプロジェクトの状況との兼ね合いになるかと思います。
ちなみにVue2.7化の軌跡も記事になっています。よければご覧ください。
② Vue3用のESLintルールを追加する
Vue3用のESLintルールを追加することで、段階的にVue3の記法を取り入れていくことができます。
特にslotの新記法に関するルールについては移行ビルド導入前に必ず直しておく必要があるため、この項目はほぼマストです。
もちろんVue2では使えないAPIの使用を強制するルールもありますが、そういうルールは一旦オフにしておけばOKです。移行ビルド導入後に一つずつ有効化して修正していく流れにすれば、作業の見通しも良くなるでしょう。
※ ESLintを活用したVue3移行についてはFUTURE株式会社様の事例がかなり参考になりました。
③ emitsオプションの追加
Vue3ではコンポーネントが発行するイベント名をemitsオプションに記述することが強く推奨されています。
これは、子コンポーネントの emits に宣言していないイベントを親側でバインドすると、子のルート要素にバインドされるようになったためです。つまりはネイティブイベントと同じ扱いになるため、意図しない挙動に変わってしまう可能性があります。emits
オプションはVue2だと単純に無視されるため、移行ビルド導入前から追加可能です。とはいえ、全コンポーネントの全イベントを記述するのは流石に辛過ぎます。そこで弊社ではemits
オプションを半自動で全コンポーネントに挿入するツールを自作して使いました(自分で使うためだけに作ったため動作は保証していません)。
ツール自作には少し時間がかかりましたが、明らかに手動で行うよりは速く、単調作業による精神的ダメージも負わずに済んだので悪くない選択だったと思います。ASTを触る勉強にもなりました。
またemits
に関するESLintルールも存在しておりエディタ上で修正提案を行ってくれるので、こちらを使うのも手かもしれません。
④ 使用しているVue関連ライブラリの調査
使用しているVue関連のnpmパッケージを洗い出しておくと後々の作業が捗ります。
具体的には各ライブラリを、
- Vue3対応済みバージョンが存在するもの
- Vue3対応していないが代替ライブラリがREADMEやIssueに記載されているもの
- Vue3対応しておらず代替ライブラリも用意されていないもの
の3種類に分けてメモしておきます。このメモが移行計画を立てる際や移行ビルド導入後に大量発生したバグの原因究明に役立ちました。
また各ライブラリをVue2で動く限界までアップグレードしておくと、移行ビルドのPRが小さくなるので吉です。
以上の作業が終わったら「Vue関連ライブラリはなるべく追加しない」といったルールを周知すると良さそうです。もちろん一つのバージョンでVue2, 3の両方に対応しているライブラリなら問題ないのですが、そうでなければせっかく作ったメモが腐るだけでなくVue3対応作業も増えてしまうので。
※ 余談ですが、Vue3未対応ライブラリの差し替えは結構面倒だったので、今後もVue関連ライブラリはなるべく入れず一般的なライブラリだけ使っていこうと思いました🫠
⑤ 自作ライブラリのVue3対応
自作のnpmパッケージやサブモジュールを使っている場合、それらのVue3対応は先にやっておいた方がいいでしょう。
プロダクトの開発を止めない場合、Vue3対応バージョンと現行のVue2バージョンを並行して開発する必要があるため、Vue3対応用のmasterブランチやreleaseブランチを別で用意し、CIなども追加する必要があるかと思います。
弊社の場合、自作ライブラリはどれも小規模だったので、移行に関してはガイドに従うだけで滞りなくできました。
また今回は行いませんでしたが、前節で洗い出したVue3未対応ライブラリをフォークしてVue3対応しておくのもいいかもしれません。他の方がフォークして独自にVue3対応したバージョンを公開していることもあるのですが、それが自分たちのプロダクトでは動かなかったりすることもあり、個人的には自身でフォークしてVue3対応した方が楽でした。
⑥ v-modelの使用を控える
v-model
周りの破壊的変更が多く苦労したのですが、実際v-model
はただの糖衣構文なので、使わないことも可能です。
特にv-model
用のpropとイベントのデフォルト名が modelValue
とupdate:modelValue
になった仕様変更への対応が大変でした。
これは、コンポーネント自体の修正だけではなく、そのコンポーネントを使っている箇所でもvalue
を渡してinput
イベントを購読する形で書かれていないかチェックする必要があったためです(v-model
が双方向バインディングであることを嫌いpropの引き渡しとイベントの購読を分けて書いている箇所が結構ありました)。
そのため、
- コンポーネントを新規で作る際にはv-model
を使える設計にせず、modelValue
を受け取りupdate:modelValue
イベントをemitする形にする
- 既にv-model
が使えるように作ったコンポーネントについては、引き続きv-model
を使う(propの引き渡しとイベントの購読を分けて書かない)
ようにすると、移行ビルド導入後の作業量が減って捗ると思います。
ちなみに先ほどご紹介したFUTURE株式会社様の事例では、ESLintルールを活用してこの変更に対する修正を安全に行われたようでした。ただしこれも一括修正できるわけではないので、やはりv-model
が少ないに越したことはなさそうです。
⑦ VueコンポーネントのテストなどCIを充実させておく
移行ビルドを導入すると、ほぼ全てのページの表示や機能が壊れると思います(少なくともうちの場合はそうでした)。そのためテストを充実させておくと安心です。
ちなみに移行ビルド導入後すぐは、テスト自体も壊れて動きませんでした🫠 こちらについては次回の記事で解説していく予定です。
移行ビルド導入前に実施できるが必須でもないこと
以下は、移行ビルドを動かすためだけなら実施しなくてもいい項目です。
ただ移行ビルドを外す前には行う必要があるので、余裕があれば先に実施しておいても損はないかと思います。
❶ 削除されるAPIの置き換え
Vue3で削除されるAPIの中には、Vue2の時点ですでに置き換え可能なものがいくつかあります。
例えば、
などです。
削除されるAPIの一覧はこちらを参照ください(全てがVue2時点で置き換え可能なわけではありません)。
❷ 引数なしのv-bindは属性の先頭に書くようにする
Vueには引数なしのv-bind
にオブジェクトを渡すことでpropsを一括指定できる機能があります。
<!--以下の2つは同じ意味 -->
<CustomInput
v-bind="{
width: 100,
height: 100
}"
/>
<CustomInput
:width="100"
:height="100"
/>
ここの仕様がVue3から微妙に変更されました。具体的には、Vue2では一括指定したプロパティは他の属性で無条件で上書きされていたのですが、Vue3からは指定方法に関わらず後に書いた属性が優先されるようになりました。
例えば以下のVueテンプレートを考えます。
<CustomInput
:width="100"
v-bind="{ width: 480 }"
/>
Vue2ではv-bind
から指定しているwidth: 480
は上書きされ結果的に100
が渡されていました。しかしVue3からは後に書いてある480
が渡されることになります。
そのため、全てのv-bind
を先頭に書いて優先度を最も低くすることで、Vue2と同じ動作を保つことができるわけです。
<!-- Vue2でもVue3でもwidthは100になる -->
<CustomInput
v-bind="{ width: 480 }"
:width="100"
/>
❸ data
の書き方変更
こちらは以前から言われていたので既に対応済みのところが多いと思いますが、data
を関数ではなくオブジェクトで持っている場合は修正が必要です。こちらもESLintで一部autofixできるようです。
❹ <transition-group>
にタグ属性を入れておく
<transition-group>
はVue2ではデフォルトで<span>
で囲まれていたのですが、Vue3からはそれが無くなりました。
Vue2とスタイルが変わらないことを保証したい場合は<transition-group tag="span">
と明示的にタグを指定すればOKです。
以上です。Vue3対応に悩む皆様のお役に少しでも立てれば幸いです。
(プロダクトによっては他にも先行対応できることがあるかもしれないので是非公式のガイドもご覧ください。)
次回は「移行ビルド導入編」を予定しています。