はじめに🙇
こんにちは、LAPRASに業務委託として参画しているWebエンジニアのしんです。
弊社の主要プロダクト(LAPRAS および LAPRAS SCOUT)ではVueを使用しているのですが、先日そのバージョンを2系最新である2.7へアップデートしました🎉
そこで本記事では、
- Vue3ではなく2.7に上げた理由
- Vue + Webpack構成での詳細なアップグレード手順
- 2.7に上げたことで得られたメリット
などを詳しく解説していきたいと思います。
公式アップグレードガイドに書いていないハマりポイントもいくつかあったので、今後アップグレードを見据えている方はぜひ読んでみてください。
なぜ3ではなく2.7にアップデートしたのか🤔
現在のVueのデフォルトバージョンは3です。
そのためLAPRAS内でも「早く3に上げたいね」という話がたびたび上がっていました。
それでも「まずは2.7に上げよう」となった理由は主に以下の3つです:
もうすぐEoLを迎えてしまうプラグインがあったため
Vue2.6でCompisition APIを使うためには@vue/composition-api
プラグインが必要ですが、これが 2022 年末でメンテが終了してしまいます。計画時点では残り2ヶ月弱しか残っていませんでした。
それに対しVue2系自体のLTSは2023年末でまだ猶予があったため、とりあえず先に2.7対応をした方が良さそうという共通認識が生まれました。
テンプレート部分の型推論がおかしい問題が直る可能性があるため
一部のプロダクトにおいて、Vue SFCのテンプレート部分の型推論がうまくいかず、TSの恩恵が十分に受けられていないという課題がありました。
例えばリアクティブな変数がtemplate
内でもRef<...>
型と推論されてしまい、正しいコードでも大量のエラーが出ていました😱
恐らくComposition API用プラグインの読み込み方が原因と思われたため、プラグインが不要になる2.7に上げることで改善するのではという期待がありました。
段階的にアップデートした方が安全なため
あとは一般論として「ライブラリアップデートはバージョンを刻め」と言われている(?)ためです。
差分が単純に減って安心というだけでなく、作業に要する時間が短縮されることでコンフリクトが減る効果も見込まれます。
アップグレードの手順 📝
※冒頭にも書きましたが、本記事で解説するのはWebpackを使用している場合の手順です。
Viteを使っている場合は全く手順が異なるためご注意ください(と言ってもViteの手順はたった 4 行なので解説も不要かもしれません)。
※また以下は全て2022年12月現在の情報です。
実際にアップグレードを行う際は本家のアップグレードガイドも参照してください。
それではアップグレードの手順を見ていきましょう。
1. @vue/cli系パッケージのアップグレード
vue-cli-xxx
的な名前のパッケージが入っている場合は、まずそれらをアップデートします(LAPRASではvue-cliを使っていないのでスキップしました)。
4系なら4.5.18
以上、5系なら5.0.6
以上にアップデートする必要があるようです。
2. Vueを2.7系の最新版にアップグレード
次にVueを2.7系の最新版にアップグレードします。
yarn upgrade vue@^2.7.0
※2.7.0
ではなく^2.7.0
です。試しに2.7.0
を入れてみたところ大量の型エラーが出たため、マイナーバージョンも最新にするのが良さそうです。
3. vue-loaderとvue-demiのバージョンを確認する
以下の二つのバージョン要件があります。
- vue-loader:^15.10.0
- vue-demi:^0.13.1
※package.json
だけでなくyarn.lock
などロックファイルも確認してください。
要件を満たしていなかった場合は、node_modules/
以下とロックファイルを全削除したあと再インストールすればいいそうです。
# バージョン要件を満たしていなかった場合のみ!
rm -rf node_modules/ yarn.lock && yarn
4. vue-template-compilerを消す
(この手順は任意です。@vue/test-utilsを使っている場合はスキップしてください)
@vue/test-utils を使っていない場合に限りvue-template-compiler
パッケージを消すことができます。
# test-utilsを使っていない場合のみ!
yarn remove vue-template-compiler
LAPRAS ではtest-utilsでテストを書いているため、この手順はスキップしました。
5. Composition APIのインポート元をvueに変える
2.6系以下でComposition APIを使っている場合、defineComponent
等のAPIを@vue/composition-api
からインポートしていると思います。
これをvue
からインポートするように変えます。
- import { defineComponent } from '@vue/composition-api'
+ import { defineComponent } from 'vue'
これはエディタの一斉置換で行うだけなので簡単でした。
次にVue.use()
している箇所も不要になるので削除します。
- import VueCompositionApi from '@vue/composition-api'
- Vue.use(VueCompositionApi)
最後にソースコードを正規表現/[cC]omposition-?[aA]pi/
で全検索して、Composition APIに関する記述が残っていないかを確認するとより安心です。
※@vue/composition-api
に依存しているパッケージを使っている場合は、アップデートしたり代替パッケージを使うなどの対応も必要になると思います。
6. 新たに発生した型エラーへの対処
(この手順は任意です。TypeScriptを使っていない場合やCIで型チェックをしていない場合はスキップ可能です)
Composition APIをvue
からインポートするようにした結果、型推論が改善され新たな型エラーが出ている可能性があります。
大量に出ていて対処に時間がかかりそうな場合は、一旦@ts-expect-error
コメントで黙らせるのも一つのやり方でしょう。
LAPRASでは凄腕エンジニアの川俣さんが作成したツールを用いて一瞬で型エラーを黙らせました。オススメです。
(黙らせた型エラーは、アップグレードが落ち着いた後に少しずつ直していきましょう)
7. eslint-plugin-vue
を最新 (9系)に上げる
(この手順は任意です。<script setup>
を使わない場合はスキップ可能です)<script setup>
を使う予定の場合は、eslint-plugin-vueのバージョンを 9 以上に上げないとLint でエラーが出ます。
yarn upgrade eslint-plugin-vue@latest vue-eslint-parser@latest
※ eslint-plugin-vueがサポートしているNode.jsのバージョンは^14.17.0 || >=16.0.0
なので、こちらも適宜アップデートが必要です
また.eslintrc
にもparser
を追記する必要があります。
{
"parser": "vue-eslint-parser"
ここで既に別のparser
を使っている場合は、それをparserOptions
に移せばいいそうです。
"parser": "vue-eslint-parser",
"parserOptions": {
"parser": "@typescript-eslint/parser",
"sourceType": "module"
}
これらを実施すると Lintルールも変わるため再度Lintをかける必要があります。
8. PostCSS周りのアップデート
2.7のSFCコンパイラはPostCSS8を使っているため、7系を前提としたプラグインを使っていると問題が起こるらしいです。
該当する場合は、適宜アップデートしたり代替パッケージを探すなどの対応が必要になると思います。
9. Volarの設定
Volar を導入した際にtsconfig.json
の設定もしたはずですが、そこも修正が必要です。
{
// ...
"vueCompilerOptions": {
- "target": 2 // 2.6までの設定
+ "target": 2.7
}
}
10. リアクティブな変数の名前を _
や$
で始めていないかチェック
ここからはアップグレードガイドには直接書いていない内容になってきます。
Vue2.7からは以下のようなコードがうまく動かない可能性があります。
setup() {
const _isReady = ref(false)
.
.
.
実行するとwarningが出ます。
なんと_isReady
は定義すらされていないことになっているようです。
これはどうも_
や$
で始まる変数名はVue の内部的なプロパティ等と衝突する可能性があるための仕様のようです。
Vue2.6 以下では問題なく動くコードであるため、ここは対応必須です(私が対応したときはwarningすら出てこなかったため大変に難儀しました)。
なお私が試した限りは、リアクティブでない普通の変数や、setup()
外の変数は_
で始まっていても問題ないようでした。
11. Webpackを最新(5系)にする
恥ずかしながらプロダクトの一つにまだ Webpack4 を使っていたものがありました。
その状態でアップグレードを試したところ「追加のローダーが必要かもしれない」というエラーが出続けコンパイルができませんでした。
まあ当然かもしれませんが、ビルドツールはアップグレード着手前に最新化しておくのがよさそうです。
12. setup第二引数contextの変更
Composition APIのsetup()
のcontext
から、root
など一部のプロパティが削除されています。
これは元々エディタ上でも「deprecated」と警告されていたため、既に対応していた人も多いかもしれません。
対応法としては、getCurrentInstance().proxy
を代わりに使う方法が知られています。
この対応はそれなりに面倒だった記憶があるので、アップグレード前に実施した方がいいかもしれません。
ー
これで完了です!
参考までに、かかった工数はLAPRAS (Vueファイル数が300ファイル程度のプロダクト) で1.5人日くらいでした。
直接アップデートに関係ないCIのエラーに半日ほど取られたので、スムーズに行けば半日〜1日で終わるのではと思われます。
Vue2.7に上げてよかった点👍
色々と良くなりました。
テンプレートの型推論が改善された
当初の目論見通り、テンプレート部分における型推論の問題が解決されました。ref
変数の型がRef<...>
になっていたのが、適切にRef
を剥がしてくれるようになり、エディタの赤線地獄から解放されました。
ESの新しめの記法がテンプレート内でも使える
以前はnull合体演算子??
やOptional Chaining?.
をテンプレート内で使うとコンパイルエラーになっていました。
Vue2.7 からはそれらが使えるようになり、不条理なエラーでストレスを受けなくて済むようになりました。
<script setup>がいい感じ
<script setup>
を使えるようになったことで、UXおよびDXの改善のための素地ができました。
例えば、`<script setup>`には普通の Composition APIと比較して、
- 記述がシンプルになる(DX)
- 型推論が速い(DX)
- 実行時も速い(UX)
など様々なメリットがあります 。
そのため今後は<script setup>
をデフォルトとすることで、開発とプロダクト両方でのパフォーマンス改善が見込まれます。
個人的にも書き味がシンプルになって好印象です。
感想🐱
公式のアップグレードガイド通りにやっていくだけでできた
「公式のガイド通りにやっているのに何故かうまくいかない」的なことってたまにあると思うのですが、Vue2.7はほぼガイド通りで OK でした。
ガイドに載ってないことも別の公式ドキュメントには載っていたりしたので、体験としてスムーズでした。
ビジュアルリグレッションテストを入れておいて良かった
LAPRASでは Percyを使って CI 上でビジュアルリグレッションテストを行っています。
上の画像のように、以前のスナップショットから見た目が変化している箇所が赤く表示されるようになっています。
この画像だと「メールアドレス」エリアがなくなって全体的に上にズレてしまっていることが見て取れます。
サイト全体に渡る修正をする際にはほぼ必須級のツールだと思います。
ー
以上です。
最後までお読みいただきありがとうございました!