Tabelog Tech Blog

食べログの開発者による技術ブログです

ts-jestからSWCへの移行で発生するイミュータブル性と型チェックの問題について

この記事は 食べログアドベントカレンダー2024 の18日目の記事です🎅🎄

はじめまして。食べログ開発本部ウェブ開発2部FEチームの中内です。
本記事では、食べログノートで使用しているJestのトランスパイラをts-jestからSWCに移行した際、既存のテストが動作しなくなる問題と型チェックについて解説します。

食べログノートとは

2023年2月に本格展開を開始した予約管理台帳です。

食べログでネット予約をご契約いただいている店舗向けのオンライン予約台帳サービスで、電話予約や各種グルメメディアのネット予約を一元管理することで、紙台帳よりも手間なく管理することができます。

詳しくはこちらをご覧ください: 食べログノートとは

移行実施の背景

食べログノートのフロントエンドは、ReactとTypeScriptで開発されています。
開発時のCI(継続的インテグレーション)において、実行時間が長いことが課題となっていました。特に、UT(ユニットテスト)の実行時間が全体の半分以上を占めており、開発プロセスのボトルネックとなっていました。
この課題を解決するため、ts-jestからSWCへの移行を実施しました。

ts-jestからSWCへの移行とその効果

ts-jestは、Jestのエコシステムの一部として、TypeScriptのサポートを提供するためにコミュニティによって開発されました。公式ドキュメントでは、TypeScriptをサポートする方法としてts-jestの説明、具体的な導入方法も記載されています。そのため、食べログノートでも利用していました。

SWCは、高速なJavaScriptコンパイラであり、特にトランスパイルのパフォーマンス向上を目的として設計されています。Rustで実装されているため、非常に高いパフォーマンスと安全性を提供します。この特徴により、SWCは大規模なプロジェクトでも高速かつ信頼性の高いトランスパイルを実現することができます。
ts-jestからSWCに移行した場合でも、食べログノートの要件を十分にカバーできているため、機能的に問題はありませんでした。

ts-jestからSWCへの移行を行った結果、テストの実行速度を大幅に向上させることができました。移行に際しては、公式ドキュメントを参考に設定を行いました。その結果、テストの実行速度を向上させることができました。時間計測の結果、以下のようにCI時間を短縮できました。

計測結果 グラフは、CIの実行時間と、その内訳を表しています。青色がUT以外の実行時間、オレンジ色がUTの実行時間です。
※移行前後でUT以外の実行時間が伸びていますが、実行毎のブレによるもので今回の修正の影響ではありません。

CI時間の比較

項目 移行前 移行後 短縮時間 短縮比率
全体のCI時間 22分7秒 12分39秒 9分38秒 43.2%
CIでUTにかかる時間 14分49秒 4分52秒 9分37秒 64.9%

ts-jestからSWCへの移行によってUT実行時間を約64.9%短縮できましたが、その過程でいくつかの問題に直面しました。次のセクションでは、具体的な問題とその対策について紹介します。

jest.spyOnの問題と対策

ts-jestからSWCへの移行すると、jest.spyOnが動作しなくなります。
Jestは、モジュールの特定の関数を監視したりモック化するために、そのモジュールのプロパティを動的に変更することがあります。SWCによって変換されたモジュールでは、これらのプロパティがイミュータブルであるため、Jestがこれらの操作を行えず、テストが失敗します。jest.spyOnもこの影響で動作しなくなります。

一方、jest.mockはモジュール全体をモック化するため、プロパティのイミュータブル性の影響を受けずにそのまま使用できます。
SWCの公式ドキュメントでは明言されていませんが、Issuesではjest.mockへ書き換える方法が提案されることが多いです。

より詳しい内容はこちらを参照してください。
SWCによって変換されたCommonJSモジュールの互換性問題に関する議論

食べログノートでは、今回の移行を検討した2024年9月時点でUTが約6000件あり、そのうち400件でjest.spyOnを使用していました。少なく見積もっても数日で終わる量ではない点、ここまでチームに浸透しているjest.spyOnを今後も使い続けたい点の2点から、書き換えはせずjest.spyOnのままテストを成功させる方法を探りました。

swc_mut_cjs_exportsの導入

食べログノートではjest.spyOnを使用し続けたまま上記問題を解決するためにswc_mut_cjs_exportsのプラグインを導入しました。
swc_mut_cjs_exportsは、SWCによって変換されたモジュールでエクスポートされたプロパティをミュータブルにすることで、Jestがプロパティを自由に変更できるようにします。
これにより、jest.spyOnのモック機能が正常に動作し、テストが成功するようになりました。

型チェックの問題と対策

SWCへ移行すると、ts-jestで行われていたテストファイルの型チェックが行われなくなります。
SWCの公式ドキュメントでは、テストの型チェックにtscを使用することが推奨されています。
そこで、食べログノートのプロジェクトでもtscを導入し、TypeScriptの型チェックをCIパイプラインにUTと並列に組み込むことで、コードベース全体の型の整合性を確保しました。

CIの比較画像

この設定により、CI時間を短縮を維持しながら、型チェックによる品質の担保も実現しました。

まとめ

ts-jestからSWCへの移行により、UTにかかる時間を約64.9%削減し、CI全体の効率を大幅に向上させました。
jest.spyOnがエラーになる問題については、SWCでイミュータブルになったモジュールのプロパティをミュータブルにするため、swc_mut_cjs_exportsプラグインを導入して解決しました。
型チェックの問題については、tscを導入し、ユニットテストと並行して型チェックを実行することで、CI時間が伸びないように工夫しました。
これらの対策により、既存テストコードを大きく修正することなく、テスト実行時間を短縮できました。

ts-jestからSWCへの移行を検討中の方の参考になれば幸いです。

明日は @soma_hi の「新卒2年目の私が素敵な設計で素敵な仕様変更に巡り会えた件」です。お楽しみに!

最後に

最後まで読んでいただき、ありがとうございました。

食べログではエンジニアを募集しています。興味のある方は以下のリンクから詳細をご覧ください。