はじめに
esbuild
の登場により、フロントエンドの世界は、開発環境により速度を求めるようになりました。vite
の隆盛はその最たるものといってもいいでしょう。
esbuild
や swc
は高速な Go
や Rust
によって書かれ、更に多くの場合、Typescript の型チェックを省略しています。
tsc
の型チェックは、大抵 IDE やワークフローで行われているので、これらを削ぎ落とすことで、純粋なコンパイラとして JavaScript
への変換に特化しているということですね。
さて、Typescript コードをテストする際、多くの場合ts-jestやbabel-jestをトランスフォーマーとして使用していると思います。しかし、これらによってテストの速度が低下することがあります。
今回は jest
の実行を高速化し、高速なテストを実現する方法を紹介します。
結論
先に導入方法について書いておきます。
トランスフォーマーに swc
を jest 向けに調整した @swc/jest
を使います。
パフォーマンス比較
高速化によって、どの程度パフォーマンスが改善したか見てみます。
CommonJS + Javascript
理論上最速となりそうなパターンを試してみます。CommonJS 形式の JavaScript はトランスパイルの必要がないはずなので、最速になるはずです。(間違ってたらごめんなさい 🙏)
関数の中身に興味はないので、適当な関数を用意してテストします。
これをキャッシュを無効にして 10 回程度の平均を取ります。 あまり厳密な測定ではないですが、今回はそれぞれの速度比較なので、条件を合わせることで相対的な比較はできていると考えます。
結果:
これを基準に考えていきます。
ESM + TypeScript
TypeScript を ES module 形式で記述するパターンです。TypeScript を使う場合の多くはこのパターンでしょう。
トランスフォーマーに ts-jest を使う
結果:
CommonJS + JavaScript と比較すると3倍程度時間がかかっています。これはなんとかしたいですね。
トランスフォーマーに esbuild を使う
esbuildは Go で記述された高速なバンドラーです。バンドラーと言ってもデフォルトで、TypeScript 構文の解析と型注釈の破棄に対するサポートが組み込まれています。
結果:
驚異的な速度ですね。特に CommonJS + JavaScript よりも早いのは驚きですね。
トランスフォーマーに swc を使う
swc は、rust で記述された超高速コンパイラです。
Denoもdeno lint
やdeno doc
に使っているみたいですね。
結果:
esbuild
も swc
も驚異的な速度でトランスパイルできることがわかります。双方の速度面の比較はこの結果だけではできませんが、調べた感じだとswc
のほうが若干有利のようでした。ただし、esbuild-jest
ではオプションとして次の項目を変更できる利点があります。
また、VSCode の場合は、jest の拡張機能が提供されています。 これは、テスト対象に変更があった場合などに、バックグラウンドで自動的にテストを実行してくれますが、当然このテストも高速になります。
テストが成功した場合、✅を対象コードにつけてくれます。テストがすぐに終わるため、すぐにマークをつけてくれるのが開発体験としてはかなりいいです。
jest.config.ts をやめる
上の結果は、jest
の設定ファイルとしてjest.config.js
を使っていました。
しかし、.ts
形式の設定ファイルにすると、トランスフォーマーを変えたとしても、パフォーマンスがあまり改善しません。
ファイル形式を .ts
に変えただけで2倍以上時間がかかるようになってしまいました。
これは jest は jest.config.ts
のトランスパイルに ts-node
を要求しているからです。
そこで可能であれば json 形式で jest.config.json
や諦めて jest.config.js
形式で設定ファイルを書く必要があります。
Cons
冒頭述べている通り、esbuild
や swc
は型チェックを省略し、速度を享受しています。よって、次のコードはテスト時にコンパイルエラーを検出できません。
この場合は、アノテーションが不適切ですが、JavaScript にコンパイルされたときには、正常のコードとして動くのでテストも通ります。
かといっても、大抵の IDE ではエラーを視覚的に表示しているはずですし、ワークフローに tsc
を追加しておけば、未然に防ぐことができます。
以上のことから、速度重視で代替手段や工夫が講じられる環境であれば、積極的に採用できるのではと思います。
Edit this page on GitHub