こんにちは。弁護士ドットコム クラウドサイン事業本部の篠田 (@tttttt_621_s) です。
普段はフロントエンドの開発を担当しています。
Vue.js を使ったプロダクト開発において、今年の課題としてあげられるものは Vue2 のサポート終了による Vue3 への移行ではないでしょうか。
弊社プロダクトの CloudSign や社内用の管理画面(以下 backyard と呼びます)も Vue.js で開発されています。
プロダクトの安定性を担保するためにも段階的に移行していく必要があります。本記事では Backyard を Vue2.7 に移行した取り組みを紹介します。
Backyard の構成
Backyard は Golang のテンプレートエンジンで生成された HTML に Vue をマウントしており、規模としては 40 画面程あります。
以下に主な技術構成を紹介します。
vue
@vue/composition-api
@vue/test-utils
jest
typescript
webpack
調査
毎週火曜日に 1 時間程度、有志のメンバーで集まり Backyard で使用しているライブラリの見直しや Vue2.7 移行に必要な周辺ライブラリの調査をしました。
やったこと
Vue2.7 に移行のためにやったことは主に以下 3 つです。 - @vue/composition-api の削除 - createApp の対応 - その他ライブラリの更新
またレビュアの負荷軽減のため Vue.js のアップデート関連以外の関心事は切り出し、小さい粒度で MR(マージリクエスト)を作成しました。
@vue/composition-api の削除
@vue/composition-api は、Vue2 用 Composition API のプラグインです。
Backyard では、約 80 ファイルほどがこのプラグインを使って実装されていました。
Composition API が組み込まれた Vue 2.7 のリリースに伴って、このプラグインは Vue 2.7 以前のバージョンのみをサポートすることになっています(現在はサポート終了)。
そのため、このプラグインをプロジェクトから削除し、Composition API のインポートを Vue 本体から行うように変更しました。
- import { ref } from '@vue/composition-api' + import { ref } from 'vue'
createApp の対応
Vue 2.7 では、Vue 3 の機能がバックポートされているため、その恩恵を受けることができます。
しかし、すべての機能がバックポートされているわけではありません。
その中の 1 つに createApp
があります。
Backyard では、これまで以下のように createApp
を使ってインスタンスを作成していました。
import { createApp } from '@vue/composition-api' import App from './App.vue' const app = createApp(App)
よって、createApp
を使っているファイルを new Vue
に置き換える必要がありました。
すべて new Vue
に書き換えるのは多少の手間がかかります。
また今後 Vue 3 に移行した際は再び createApp
を使用することになるので、new Vue
を内包したモジュールをプロジェクト内に作成しそれを使用することにしました。
import Vue from 'vue' export const createApp = (params) => { return new Vue(params) }
- import { createApp } from '@vue/composition-api' + import { createApp } from '@modules/createApp' import App from './App.vue' const app = createApp(App)
eslint-loader から eslint-webpack-plugin へ移行
eslint-loader は webpack の ESlint 用のローダーです。
こちらのリポジトリは、すでにアーカイブされているため非推奨となっています。
よって webpack.config.js を修正し、eslint-webpack-plugin へ移行しました。
+ const ESLintPlugin = require('eslint-webpack-plugin') module.exports = (env, options) => { return { module: { rules: [ - { - enforce: 'pre', - test: /\.(js|vue)$/, - exclude: /node_modules/, - use: [ - { - loader: 'eslint-loader' - } - ] - }, ] }, plugins: [ + }), + new ESLintPlugin({ + extensions: ['.js', '.vue', '.ts'] }) ], } }
@vue/test-utils と typescript のアップデート
Backyard のユニットテストは以下のように @vue/test-utils を使用しています。
<template> <div> <h1 data-test-message>{{ message }}</h1> </div> </template> <script lang="ts"> import { defineComponent, ref } from 'vue' export default defineComponent({ setup() { const message = ref('Hello') return { message } } }) </script>
import App from './App.vue' import { mount } from '@vue/test-utils' describe('App.vue', () => { test('Hello と表示されていること', () => { const wrapper = mount(App) expect(wrapper.find('[data-test-message]').text()).toBe('Hello') }) })
Vue2.7 にアップデートすると、ビルド時にテストファイルで以下のような型エラーになりました。
TS2321: Excessive stack depth comparing types 'Vue3Instance<Data, Readonly<ExtractPropTypes<{}>>, Readonly<ExtractPropTypes<{}>>, {}, {}, true, ComponentOptionsBase<any, any, any, ... 6 more ..., any>> & ... 5 more ... & Readonly<...>' and 'Vue<Record<string, any>, Record<string, any>, never, never, (event: string, ...args: any[]) => Vue<Record<string, any>, Record<string, any>, never, never, ...>>'.
こちらに関しては地道に検証し @vue/test-utils と typescript を以下のバージョンまでアップデートすることで解消しました。
- "@vue/test-utils": "1.3.0",
- "typescript": "4.3.2",
jest のアップデート
Vue 2.7 移行とは直接的には関係ありませんが、ついでにテスト環境も改善したいと考え、今回 jest のバージョンを 27 にアップデートしました。jest は、バージョン 27 でデフォルトの挙動に変更が入っています。
今回影響があったのは以下で、それぞれ対応をしました。
- testRunner が jest-jasmine2 から jest-circus に変更
- testEnvironment が jsdom から node に変更
testRunner が jest-jasmine2 から jest-circus に変更
jest-circus は、done コールバックをサポートしていません。 実際に以下のような記述があるテストは失敗するようになりました。
beforeAll(async (done) => { await flushPromises() done() })
引き続き testRunner で jest-jasmine2 を使用するため、以下のように設定を追記しました。
"jest": {
+ "testRunner": "jest-jasmine2"
}
testEnvironment が jsdom から node に変更
testEnvironment の変更により、DOM API を使うテストが失敗するようになりました。 こちらも、引き続き jsdom を使用するため以下のように設定を追記しました。
"jest": {
"testRunner": "jest-jasmine2"
+ "testEnvironment": "jsdom"
}
おわりに
CloudSign の社内用の管理画面を Vue2.7 に移行した取り組みを紹介させていただきました。
今回紹介しきれなかったことも多々ありますが、Vue2.7 に移行したことでプロダクトの安定性の担保や開発者体験の向上に繋がったと考えています。
今回のような改善活動は有志のメンバーで行われていましたが、この度フロントエンドの改善に特化したチームが新設されました。
Vue2.7 移行は Vue 3 に向けての最初の 1 歩となりました。今後も少しずつ歩んでいきます。
最後まで読んでいただき、ありがとうございました。
クラウドサインのフロントエンドに興味があるという方をお待ちしております。