はじめに
前回に続き、ライブラリの更新関連についての内容となります。
前回の記事
今回は特に手間がかかったUIライブラリの更新に関してです。
UIライブラリの更新
今回のVue3対応で一番問題が大きかったのが、UIの基本的なパーツで使用していたライブラリの更新でした。
ライブラリのSCSSを取り込んで自前で書き換えている箇所が多々あるうえに、個々のコンポーネントのスタイル指定からも上書きしている箇所があり、何も気にせず更新すると画面が大幅に崩れてしまう状況でした。
なにも対策なくすると元通りにならないかつ、工数もかかってしまうため、今回は以下のような対応を実施しました。
- ライブラリのSCSSをVue2時点の改変後と同等になるようにマージ+手直し
- Storybookの導入
- パーツ単位での見た目、動作確認
- 確認のために作成したストーリーを使用し、VRTを実施
SCSSのマージ+手直し
ライブラリ側がVue3対応に伴いIE対応を外したため書き方が大幅に変更されていました。
特にCSS変数の導入で作りが変わっている箇所が多く、機械的にマージができませんでした。
こればかりはどうしようもなく、ひたすら手作業で内容を見比べてどこにマージするべきかを考えながらのマージ作業を行いました。
一通りマージし終えてから実際の画面を見てみたときは、マージ前に比べるとましではあるものの、まだ所々崩れがありました。
この辺りは、ひたすら後述するVRTの実施、検出された問題の修正の繰り返しで対応していきました。
Storybookの導入
ライブラリの更新による問題だけでなく、各画面が一通り表示できる状態にならないと動作確認できない点や、一部ローカルでは確認が難しい画面などがありました。
そこで対象の画面やパーツ以外の部分にとらわれず確認や修正を可能にするためStorybookを導入することにしました。
Storybookとは表示するためのページなどを用意せずとも、対象のパーツの表示や動作確認、テスト、ドキュメント作成などが行えるツールで、フロントエンドの開発を行っているとよく耳にするものかと思います。
導入に関しては、基本的にライブラリのバージョン一式更新していたため、Storybookの導入は公式の手順通りであっさりとできました。
環境ができあがれば、サンプルのストーリーと、残り全コンポーネント分のファイルのみ作成しコミットしました。
中身はコンポーネント名の部分の置き換えとpropsの指定を追加すれば最低限のストーリーが作成できるような状況にしておいたため、各メンバーで対象のコンポーネントのVue3化ができれば少しの修正ですぐに動作確認が取れる状態となりました。
一部storeを参照している箇所は直接対象のstoreの値を更新することで、任意の表示を行いました。
またWebAPIを実行している箇所についてはMSWを導入し、サーバーがなくとも動作するようにしました。
const meta: Meta<typeof HogeForm> = {
title: "components/HogeForm",
component: HogeForm,
render: args => ({
components: { HogeForm },
setup() {
// 直接更新可能な場合はここで任意の値を設定
const user = useUserStore();
auth.ability.update([]);
return { args };
},
template: `
<HogeForm v-bind='args' />
`
}),
argTypes: {},
args: {
visible: true
}
};
Storybook導入のおかげで動作確認が迅速に行えるようになりとてもよかったと思います。
VRTの実施
VRTとはVisual Regression Testの略で、対象画面の変更前後のキャプチャ画像を比較することで、意図しない差分が発生していないかを確認するためのテストです。
今回は作成したストーリーごとにキャプチャを取得して差分を確認するようにしました。
対応するにあたって変更前のキャプチャが必要です。
つまりは置き換え前のVue2側で同等のストーリーを表示できる環境の用意が必要でした。
そこでVue2側のプロジェクトにてStorybookの動作に必要なライブラリを一式Vue3側で適用したものを取得し、そこから順にVue2側の各ライブラリのバージョンで動く程度のバージョンになるよう、少しバージョンを落としては確認を繰り返して動作するバージョンを適用しました。
(最終的に適用したStorybookのバージョンは6.5.16でした)
動くバージョンが定まれば、Vue3側で適用していたmain.tsとpreview.tsをVue2側に移植し、ライブラリの指定など手直しが必要な箇所を修正してテスト用のストーリーが動作していることを確認しました。
これでVue2側の環境でもStorybookが動くようになりました。
ただVue3側のストーリーの構文がそのままでは動作するものではなかったため、Vue2用に手直しが必要でした。
可能な限り自動で対処するため、ほぼ全てテキストエディタの置換機能で置き換えていきました。
renderのsetup処理内でstoreを変更している箇所など、一部手動で手直しが必要な箇所もありましたが、あまり多くはなかったためなんとか追加コスト少なくVue2側のストーリーが作成できました。
importの修正
import type { Meta, StoryObj } from "@storybook/vue3";
↓
import { Meta, StoryObj } from "@storybook/vue";
type定義の修正
type Story = StoryObj<typeof Badge>;
↓
type Story = StoryObj<typeof Badge | Props<typeof Badge>>;
renderの中身修正
render: args => ({
components: { Badge },
setup() {
return { args };
},
template: "<Badge v-bind='args'/>"
})
↓
render: (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { Badge },
template: `<Badge v-bind='$props' v-on='$props' />`
})
これでVue2とVue3両方で同等のストーリーが動作する状態となったため、storycapを使用してキャプチャを取得し、reg-cliで差分を検出するVRTの実行ができるようになりました。
あとは毎朝VRTを実施するようにして、日々Vue3コードに置き換え完了した画面のチェックを行い、差分があれば修正することを繰り返しました。
Vue2側までの導入は大変でしたが、これにより検証コストを大幅に抑えられたと思います。
特に数ピクセルのずれの見落としが多く、VRT実施時に見つけることがあったため、そういった面でも無理して導入してよかったと思いました。
まとめ
前回に引き続き、今回も各種ライブラリ更新関連の内容でした。
UIライブラリの更新は着手前の時点でVue3への書き換えよりも大変だと考えていたため、効率的に確認できるようになり、工数削減につながりました。
また、UIライブラリの更新はVue3対応後も実施しているため、その際の確認用としてVRTが活躍しています。