jestのtransformIgnorePatterns（設定）を日本語で正しく読み解く

## 本記事の趣旨

タイトルの通りです。

React Nativeでjestを使うときにカスタマイズすることの多い、`transformIgnorePatterns`について、理解が難しく、勘違いして定義したことが原因で長時間詰まってしまいました…
きっと我が同胞がこの世界のどこかにはいると思ったため、本記事を書くに至りました。

公式ドキュメントを参照しながらわかりやすくまとめるので、お付き合いいただけたら幸いです！

※ jestの`transformIgnorePatterns`について公式ドキュメント

https://jestjs.io/ja/docs/configuration#transformignorepatterns-arraystring

## 目次

1. 最初から結論
1. 公式ドキュメントから読み解く
1. どんなモジュールをトランスコンパイルして、どんなモジュールをトランスコンパイルさせないか
1. トランスコンパイルさせるべきライブラリをどうやって判断する？（自分なりの解決法）
1. まとめ


## 最初から結論

ずばり、`transformIgnorePatterns`に定義するべきなのは、、

**トランスコンパイルさせたくないモジュール**

です。

「いや、`transformIgnorePatterns`って書いてるんだから、読んでそのままじゃない？」と思った方。
その通りです。その通りなんですが、正規表現苦手マンからすると、サンプルが難しくてよくわからなくなっちゃったんですよね。

もっと詳しく言うと、下記の通りに`transformIgnorePatterns`の配列内に定義すればオールOKです！
```
"transformIgnorePatterns": ["/node_modules/(?!(foo|bar)/)", "/hoge/"]
```
- トランスコンパイルさせたいモジュール: `node_modules/(?!(foo|bar)/)`
- トランスコンパイルさせたくないモジュール: `hoge/`

以下の項目では、公式ドキュメントからそのように読み解く過程をご説明します。

## 公式ドキュメントから読み解く

例えば、公式では下記のように定義すると言っています。
```
{
  "transformIgnorePatterns": ["/node_modules/(?!(foo|bar)/)", "/bar/"]
}
```

これについて、公式では、下記のように解釈すると言っています。
> The first pattern will match (and therefore not transform) files inside /node_modules except for those in /node_modules/foo/ and /node_modules/bar/. The second pattern will match (and therefore not transform) files inside any path with /bar/ in it. With the two together, files in /node_modules/bar/ will not be transformed because it does match the second pattern, even though it was excluded by the first.

いや、正規表現苦手マンが英語わかるわけがないんですよ。（暴論）
少なくても僕はわかりませんでした。

でも、よくよく読めば、下記のように解釈できます。
> The first pattern will match (and therefore not transform) files inside /node_modules except for those in /node_modules/foo/ and /node_modules/bar/.

→ 「最初のパターン（`"/node_modules/(?!(foo|bar)/)"`）は`/node_modules/foo/`と`/node_modules/bar/`以外がマッチする（それゆえ、トランスフォームしない）」
→ つまり、「`/node_modules/foo/`と`/node_modules/bar/`はトランスフォームする」ということ

この正規表現（`(?!(foo|bar)/)`）は、否定先読みと言って、後にくるパターンは弾くってことみたいなんですよね（参照: https://www-creators.com/archives/2746）。

そのため、「`/node_modules/foo/`と`/node_modules/bar/`はトランスフォームする」ということになるのです。（ただし、2つ目のパターンで`/bar/`はトランスフォームしないと言っているので、結局`/node_modules/bar/`はトランスフォームされません。）

## どんなモジュールをトランスコンパイルして、どんなモジュールをトランスコンパイルさせないか

そもそも、デフォルトでは`node_modules`を全てトランスコンパイルしないようになっています。
それでは、それをカスタマイズするとして、「どんなモジュールをトランスコンパイルして、どんなモジュールをトランスコンパイルさせないか」の判断基準が気になるところです。

この点に関して、公式ドキュメントの下記の一文を読み解けば理解できます。

> Sometimes it happens (especially in React Native or TypeScript projects) that 3rd party modules are published as untranspiled code. Since all files inside node_modules are not transformed by default, Jest will not understand the code in these modules, resulting in syntax errors. To overcome this, you may use transformIgnorePatterns to allow transpiling such modules. You'll find a good example of this use case in React Native Guide.

要は、

**React NativeやTypeScriptのプロジェクトにおいて、ちょくちょくトランスコンパイルしていないモジュールがあるから、それらはトランスコンパイルしてあげる必要があるよ**

と言うことです。


それ以外は基本的にトランスコンパイルしないのです。

## トランスコンパイルさせるべきライブラリをどうやって判断する？（自分なりの解決法）

これについては、公式で「`transformIgnorePatterns`を設定した方がいいよ」と言ってくれるパターンもあるんですが、だいたい書いてなかったりします。

【公式で書いてくれてるパターン】: Jest公式の「React Nativeアプリをテスト」

https://jestjs.io/ja/docs/tutorial-react-native#transformignorepatterns-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0


そのため、僕は

**テスト対象のファイルで使用しそうなライブラリは全部トランスコンパイルさせる**

という力技の方針をとっています。

例えば、`react-navigation`というモジュールを使ったファイルをテストするのであれば、`react-navigation`を`'node_modules/(?!(jest-)?@react-native|@react-navigation)'`という感じで追加します。

## まとめ

本記事では、jestの設定ファイルである`transformIgnorePatterns`についてまとめました。

**React Native**や**TypeScript**のプロジェクトでは、ちょくちょく詰まる問題だと思うので、少しでも皆さんのお役に立てると嬉しいです！