【Unit4 ブログリレー 1日目】
Viteは"ヴィート"と読みます♫ もう覚えましたね♫*1
こんにちは、エムスリーエンジニアリンググループの山田(@Satoki_1226)です。
本日より、Unit4でもブログリレーを行うこととなりました。Unit4は医療系ポータルサイト m3.com の開発・運営を担当するチームです。Unit4エンジニアがリレー形式でテックブログを執筆し、どんなメンバーがいるのか・どのような開発をしているのかなど、ご紹介できればと思います。
トップバッターである私からは、m3ラウンジというサービスのVite移行時に得られた知見をもとに、
- Vite/Vitestへの移行によって感じた「速さ」
- 移行時の手順とポイント
をお伝えできればと思います。Viteが気になっている方や、Vite移行の進め方に困っている方にとって少しでも参考になれば幸いです。なお掲載しているサンプルコードは、記事向けに簡略化と改変をしています。
m3ラウンジ
m3ラウンジとは簡単に言えば医師限定、そして実名をベースにしたオンラインコミュニケーションサービスです。m3.comの会員基盤をベースに、組織や地域、世代の枠を超えて医師の交流が広がる場となることを目指しています。m3ラウンジはフロントエンドをVue.jsで開発しており、サービスローンチ時はVue CLI Serviceを利用していましたが、先日ViteとVitestに移行しました。ここからはViteとVitestに焦点を当てますが、サービスの構成などに興味を持っていただけた場合はぜひ下記の記事も参照してください。
Viteは速い
ViteはネイティブESMを利用しています。その結果、アプリケーション全体を事前にバンドルする必要がなくなり、開発サーバーの起動を速くします。ソースコードが変更された際のHMRも同様にネイティブESM上で行うため、更新に伴うバンドルの再構築も高速化します。
実際に開発サーバーの起動時間を比較したものが以下になります。時間はm3ラウンジのものです。
ツール | 起動までの時間 |
---|---|
Vite | 0.6秒 |
Vue CLI Service | 29秒 |
見ての通り、圧倒的にViteが速いです。時間でいえば30秒程度ですが、この差は見過ごせません。開発サーバーの起動に30秒かかると、起動待ちの時間にSlackを確認したり、コーヒーを淹れたりと、他の作業を始める人もいらっしゃると思います。Slackの確認を始めたら気づかぬ間に10分、20分と経過していることもあるのではないでしょうか?Viteではそういった事がなくなります。すぐに開発サーバーを起動できるため、開発のリズムが良くなると感じました。
Vitestも速い
VitestはViteを利用したテストフレームワークです。以下の2点において「ユニットテスト開発の速さ」を感じました。
watch mode
Vitestはデフォルトの設定時、watchモードでテストを実行します。watchモードにおいては、テストの実行後もファイルの変更を検知すると関連のある部分のみを自動的に再実行します。ここでVite serverが威力を発揮します。ViteのHMRが高速であるため、テストの再実行も非常に速く、自身の変更が即座にテスト結果として反映されるため、リズムに乗って開発を進めることができます。リズムに乗るどころか、Vitestに置き去りにされる感覚を覚えることもあるため、実装を早く終わらせる力が身につきます。
UI mode
Vitestの実行時にuiオプションを指定することで、テストの実行結果をVite serverの提供するUI上で確認できます*2
vitest --ui
デフォルトではlocalhost:51204/__vitest__/
でUIエディタが開きます。もちろんターミナル上でもテストの結果は確認できますが、ターミナルをスクロールして失敗したテストを探す手間が省けます。また、テストコードの修正と再実行をVitest UI上で行うことも可能です。
CIも速くしたい
実装のリズムを速めたら、次はCIも速めたくなりますね。これはJestにもある機能ですが、shardオプションを利用することでユニットテストの分割実行が可能です。
vitest --shard <shard>
例えばshard数を4にした場合、全体のテストを4分割して並列実行できるため、CIにおけるテストの実行時間を短縮できます*3。m3ラウンジではGitLabを利用しているため、ここではGitLab CIにおける設定ファイルの記載例を示します。
test: stage: test + parallel: 4 script: - yarn install + - yarn test:unit --shard $CI_NODE_INDEX/$CI_NODE_TOTAL - - yarn test:unit
ただし注意点として、分割実行した場合、テストカバレッジが下がる傾向にあります。coverageThresholdを設定している場合、本来は問題ないカバレッジが下がってテストが失敗する、なんてこともあります。この問題を解決するためには、nyc を利用して各shardのカバレッジレポートを一度マージし、マージされた結果を元に出力するなどの対応が必要です。以下に例を載せておきます。
# test実行ジョブに追加 test: stage: test parallel: 4 script: - yarn install - yarn test:unit --shard $CI_NODE_INDEX/$CI_NODE_TOTAL + - mv src/coverage/coverage-final.json src/coverage/$CI_NODE_INDEX.json + artifacts: + paths: + - vue/src/coverage/
# ジョブの実行後にカバレッジをマージするジョブ coverage: stage: test needs: - test script: - yarn install - mkdir -p vue/src/coverage-result - npx nyc merge src/coverage/ src/coverage-result/merge.json # 分割されたカバレッジをマージ - npx nyc report --reporter=text-summary -t src/coverage-result/ # マージされた結果を元に出力 coverage: '/Statements : (\d+\.?\d*)%/'
なおすでにお気づきかもしれませんが、CIを速くするための分割実行なのに、結果的にジョブが増えています。最終的にどちらが速いのかはよく考えましょう。
移行時のポイント
ここまで、ViteとVitestによる開発の速さについて説明してきました。ここからは、移行における手順とポイントを記載します。
Vite移行の手順とポイント
の3つが主な手順です。
ここでは3について、個人的にポイントと感じた点を記載します。Viteは設定の容易さも売りの1つですが、もともとwebpackやvue.config.js
で複雑な設定をしていた場合、残念ながら設定パズルから逃れることはできません。
debug mode
起動時にdebugオプションを指定することで、デバッグログを出力できるため、移行中は付与することをおすすめします。
vite --debug
「とりあえずViteにしたら画面が真っ白…」という場合などは、ログを確認すると原因がわかるかもしれません。実際、僕は自身の書いた設定によってリクエストが意図せぬ形でモックされていることに気づくことができました。
マルチページビルド
m3ラウンジには、PC向けとスマートフォン(以下SP)向けの2つのエントリーページがあります。そのためマルチページへの対応が必要になりますが、Viteではvite.config.ts
のbuild
オプションにrollupOptions
を指定することで、複数のページをビルドできます。Viteは本番向けビルドにRollupを利用しているため、Rollupのオプションを指定します。以下に例を載せておきます。
export default defineConfig({ build: { rollupOptions: { input: { pc: resolve(root, 'pc-index.html'), sp: resolve(root, 'sp-index.html'), }, }, }, })
上記の例では、PC向けとSP向けにそれぞれpc-index.html
とsp-index.html
を用意してビルドしています。その上で、別途nginxの設定でPC向けとSP向けの振り分けを行っています。Viteはプロジェクトルートにあるvite.config.js(ts)
の設定をもとに、index.html
ファイルをアプリケーションのエントリーポイントとして扱います。Vue CLI利用時にpublic/
に配置していたindex.html
はデフォルトの設定では認識されません。m3ラウンジではsrc/
をrootに設定した上で、src/
配下にpc-index.html
とsp-index.html
を移動させました*4。
なお、PCサイトとSPサイトの構成について気になる方は、下記の記事も参照してください。
www.m3tech.blog
開発サーバーの設定
フロントエンド開発において、バックエンドへのリクエストをモックして開発することも多々あると思います。m3ラウンジにおいても、webpack-dev-serverを利用してAPIをモックしていました。Viteにもデフォルトでserverが用意されており、ここにAPIモックを追加できます。
// webpack-dev-serverの設定例 setupMiddlewares(middlewares, devServer) => { devServer.app.get("/api/v1/my-api", (req, res) => { return res.writeHead(200).send(JSON.stringify({})); }); }
// viteの設定例 configureServer(server) { server.middlewares.use((req, res, next) => { if (req.url?.startsWith("/api/v1/my-api")) { return res.writeHead(200).end(JSON.stringify({})); } next(); }); },
ビルドされるアセット
ビルドで生成されるアセットの配置先はassetsDir
、またはrollupOptions
のoutput
で指定できます。デフォルトではassets/
配下になります。パスペースでのアクセス制御を入れている場合、Vue CLIの利用時と配置先が変わる可能性があるので注意が必要です*5。
Vitest移行の手順とポイント
最後に、Vitestへの移行についてです。VitestはViteを利用しており、Jestとの互換性も意識して作られています。m3ラウンジではユニットテストのライブラリとしてvue-test-utilsを利用していますが、比較的容易に移行できました。
の3つが主な手順です。ポイントは、3においてVitest専用の設定ファイルが不要であることです。Vite移行時に作成したvite.config.ts
にテスト用の設定を追加することで、Vitestの設定ができます。
+ /// <reference types="vitest" /> export default defineConfig({ + test: { + // vitestの設定 + }, })
Vitest用にvitest.config.ts
を作成して設定もできますが、同じファイルに書くことが推奨されています*6。その他、移行の際にはマイグレーションガイドも参考にしてください。
終わりに
ここまでお読みいただき、ありがとうございました。ViteやVitestについては、まだ公式ドキュメントだけでは扱うのが難しい場面もあると思いますが、本記事が少しでも役に立てば幸いです。
We are hiring!
エムスリーには今回出てきたm3ラウンジをはじめ、多種多様なサービスと技術があります。興味を持っていただいた方は、下記よりお問い合わせください。 jobs.m3.com