JavaScript+Vue.jsの品質向上のためにしている基本的で大事な5つのコト
こんばんは、今季アニメは『ぼっち・ざ・ろっく!』が面白いね。井上(@ino_dev)です。
TechCommit AdventCalendar2022の2日目として、1日目のKenjiさんによる「React と Web Components の共存方法について」というのに続いて今日はWebフロントエンド周りの話をします。
TechCommitの開発で最近やっているJSの品質向上の取り組みについて、基本的なことを中心にざっくり紹介していこうかと思いますので、これからWebのフロント周りに力を入れる方や勉強中の方の参考になれば幸いです。
1. コンポーネントやメソッドの責務をちゃんと分ける
Vue.jsやReact.jsなどでコードを書いていても、密結合なコンポーネントが、亜熱帯ジャングルよろしく生い茂っていると、どんなに気をつけていてもバグはでます。(コンポーネント化していないならよりしんどい)
Vue.jsで一番わかり易い観点で言えば、
あたりは出来るだけ別コンポーネントに切り分けます。
TechCommitでも同じ見た目なのに他の動作が微妙に違うがために大部分がコピペのように作られている処理があるため、APIで取得するだけの処理とそのデータを流し込んで使う部分などに切り分けていっています。
責務を細かく分けるのは、コンポーネントの再利用性を高めるなどの狙いもありますが、最近Vue.jsのテストで使うVueTestUtilsでmethods等をオーバーライドすることが非推奨になっているのでそれに従うようにしているということがあります。
https://v1.test-utils.vuejs.org/api/wrapper/setmethods.html
methods等の処理をモックするのではなく、Componentごとモックで置き換えたりしてテストが書きやすいようにしたいという狙いです。
これによりcreatedなどのライフサイクル上の動作もテストしやすくなるはずです。
2. Jestでテストをちゃんと書く
コンポーネントをきちんと分けていけば、ある程度自動テストも書きやすくなります。
TechCommitではJSの処理がそもそも多くなかったというのもありますが、初期はJSは単体テストすらほぼ無かったので、Jestを導入してテストがない部分からリファクタリングと並行してテストを拡充しています。
基本的にテストしづらいコードは悪いコードであることが多いため、徐々に1のルールで切り分けを中心としたリファクタリングも加えつつ、カバレッジ率を上げながらフロント環境をリメイクしています。
主なテストの観点としては、下記内容を書いていきます。
過去にライブラリのアップデートでいつのまにか壊れていた機能などもあったので、SnapShotテストをパターンを網羅するように導入しました。
(なお、まだ出来ていませんが、APIに関しては全てモック化しており、RepositoryでOpenAPIの隙間駆動開発でインターフェースのテストを別途追加していこうとしています)
3. 結合テストをちゃんとやる
GitHubのPRに確認する事項を整理して、チェックボックスをつけています。
↓は簡単な例ですがこんな感じにまとめて、その後レビュー依頼を出します。見た目が変わる場合などはスクショやGifアニメでどのように変わったかも記載します。
改めて観点の整理・確認をまとめると、セルフレビューによって考慮漏れが検知しやすいだけでなく、他の人のコードレビューの物理的・心理的負荷を下げられるという効果もあります。
なお、先日書いた↓に近い取り組みですので、こちらも興味ある方は見てみてください。
4. CIをちゃんと回す
こちらも基本的なことですが、ローカルのprecommit(lefthook)とCI(GitHubActionsのworkflow)をきちんと回すことで自動テストのJestとLintのESLintなどを回しています。
ESLintやStyleLintは必須として、それ以外のコードフォーマッター(Prettierなど)は任意にしています。
なお、StyleLintの初期設定は下記で作成してからカスタマイズを行うのが便利でした。
https://maximgatilin.github.io/stylelint-config/
5. Sentryでエラー管理をちゃんとする
どんなに頑張ってもバグは出るときは出るので、バグが出ても出来るだけ早く気付けるようにエラー管理やパフォーマンス監視ができるSentryの設定もしておきます。
(1)エラー通知処理
画面上で起きたJS系のエラーなどを取得できる用に共通処理に下記を埋め込んでおきます。
// Sentryの初期化
Sentry.init({
dsn: process.env.SENTRY_DNS,
integrations: [
new Integrations.BrowserTracing({
tracingOrigins: ['localhost', 'tech-commit.jp']
})
],
tracesSampleRate: 0.1
})
https://docs.sentry.io/platforms/javascript/
Vue.jsのコンポーネント内の処理としてエラーを取得したい場合は基本的に、
import * as Sentry from '@sentry/vue’
として、APIのキャッチ処理などで
catch(error => (Sentry.captureException(error)))
などをつけています。
処理によっては(Slackに通知してるとうるさいので)ログレベルを変更するのが良いかと思います。
https://docs.sentry.io/product/sentry-basics/integrate-backend/capturing-errors/
(2)ソースマッピング処理
本番デプロイ時点でのbuildしたコードをSentryに送り、エラーが起きたときに全てのコードでどの部分のGitHubのコードなのか参照できるようにCodeMappingしてデバッグもしやすいようにしておきます。
TechCommitは現状RailsのWebpacker(Webpack)で動いているので、SentryWebpackPluginを導入して下記のような設定をしています。
// config/webpack/production.js
// …中略
const SentryCliPlugin = require('@sentry/webpack-plugin')
environment.plugins.prepend(
'SentryCliPlugin',
new SentryCliPlugin({
project: 'project_name',
org: 'orgname',
authToken: 'SentryToken9999999999999999999999999',
include: ['./app/javascript/', './public/packs/js'],
})
)
// ソースマップを生成&コードにSourceMappingURLは含めない
module.exports.devtool = 'hidden-source-map'
// …中略
なお、開発環境ではデモ用に下記のように設定しておくと、ソースマッピング処理自体のデバッグもはかどります。
// config/webpack/development.js
// …中略
const SentryCliPlugin = require('@sentry/webpack-plugin')
environment.plugins.prepend(
'SentryCliPlugin',
new SentryCliPlugin({
project: 'project_name',
org: 'orgname',
authToken: 'SentryToken9999999999999999999999999',
include: ['./app/javascript/', './public/packs/js'],
debug: true,
dryRun: true // 実際にuploadして動作を見たい場合はOFF
})
)
module.exports.devtool = 'source-map'
まとめ
どこでもやっているような内容ではあると思いますが、まだ本格的にWebフロントエンドの開発をしていないところではざっとロードマップ的に使っていただけたらと思っています。
コンポーネントやメソッドの責務をちゃんと分ける
Jestでテストをちゃんと書く
結合テストをちゃんとやる
CIをちゃんと回す
Sentryでエラー管理をちゃんとする
という流れで見てきました。
これから色々導入される方の参考になる部分があれば幸いです!
それではTechCommit AdventCalendar2022の2日目の記事でした。
(JestやCI周りの話や最近のTechCommit内のLTや、週末勉強会でも扱っているので、良かったらメンバーの方はそちらも合わせてご覧くださいね!)