SplittingFlowFlow導入Flowの型アノテーションJestJestインストールJestセットアップJestのテスト作成スナップショットテストEnzymeReactとReduxを学ぶために、開発環境というかプロジェクトテンプレートをスクラッチから作っている。(最終的な成果はGitHubに置いた。Routerをセットアップした。今回は残りの要素をまとめてかたづける。Splittingwebpackでリソースをバンドルすると、一回の通信でアプリの要素全てをロードできるので効率いいような気がするけど、アプリの規模が大きくなってくるとバンドルサイズが大きくなって、初期ロード時間が長くなり、つまり初期画面の表示に時間がかかるようになってしまう。そもそも、いつもアプリの全画面をみるとは限らないので、いつもアプリの全要素をロードするのは無駄。バンドルを分割し、(理想的には)必要な時に必要な分だけロードする技術。Suspenseとwebpackのプリフェッチディレクティブを使ったやつを、フォントモジュールに適用してみる。App;コード変更はこれだけ。import()がダイナミックインポートで、ECMAScriptで現在策定中の機能。これを使えるようにするためには、Babelのプラグインを追加する必要がある。}ダイナミックインポートの設定も完了。これでフォントモジュールはメインのバンドルとは別ファイルになり、初期画面の表示時にはロードされず、ブラウザの空き時間に非同期にロードされるようになる。FlowReactに限らない話だけど、JavaScriptは動的型付け言語なので、特に規模が大き目なアプリを開発するとなると保守性が悪くなりがちで辛い。できれば静的型付けでやりたい。JavaScriptを静的型付けにするには、TypeScriptとFlowという二つの選択肢がある。今回、FlowがReactと同じくFacebook製なので、Reactと相性がいいかと思ってFlowを選択したけど、人気やエコシステムの充実度から見るとTypeScriptのほうがよかった気がする。Flowについてはさらっと書く。Flow導入Flowは、ソースに型情報を付けて静的型チェック可能にしつつ、実行時には型情報を取り去って普通のJavaScriptとして実行できるようにする仕組み。型チェックするツールはflow-binパッケージで配布されていて、型情報の除去は@babel/preset-flowを使ってBabelでできる。flowでFlowを実行できるようになった。@flowと書けばとりあえず機能する。Flowの型アノテーションそれだけでもだいぶ型推論してくれてチェックが利くけど、型アノテーションを書いていくとよりいい。アノテートするとESLintとけんかするので、それ対策としてeslint-plugin-flowtypeを入れる必要がある。};例として、Reactコンポーネントのpropsに型を付けてみる。MyDialog;こんな感じで型を付けておくと、MyDialogに渡すpropsを間違った場合にFlowがエラーにしてくれる。prop-typesによる型定義と冗長な感じに見えるけど、Flowは静的に型チェックするのに対し、prop-typesはアプリの動作中に型チェックしてくれるので、両方書いておくのがよさそう。(Flowの型定義からprop-typesの定義を生成してくれるbabel-plugin-react-flow-props-to-prop-typesというのがあるけど、サポートされていない型があるし、メンテされていないし、微妙。)上のコードで、typeというキーワードで型を定義しているんだけど、Reactとかの3rdパーティライブラリの型情報(libdefと呼ばれるもの)は、ライブラリ開発者などが作ったものが公開されていて、インストールして利用できる。libdefはそれようのリポジトリで管理されていて、flow-typedで引っ張れる。installこれで、package.jsonに書かれている依存(devDependenciesを除く)を見て、必要なlibdefをダウンロードしてきて、プロジェクトルートのflow-typedというディレクトリにインストールしてくれる。さっきのReactコンポーネントのコードに、ReactのAPIの型の一つであるNodeを書くと以下のようになる。MyDialog;因みにflow-typedディレクトリの中身はコミットすることが推奨されている。なんか違和感あるんだけど...JestReactプロジェクトでユニットテストを書くなら、Jest一択でいいっぽい。JestもReactと開発元が同じFacebookで、Reactと相性がいいはずだし、Reactプロジェクト以外でもJestは人気。ゼロ設定で使えるように作られていて、導入の敷居が低いのが特徴。多機能で、アサーション、モック、カバレージ測定辺りは組み込まれていてすぐ使える。(今も?)Jasmineベースで、APIが似た感じなので、JasmineとかMochaに慣れた人には特に使いやすい。JestインストールReactプロジェクトでJestを使うには以下のパッケージを入れる。ReactコンポーネントをピュアなJavaScriptオブジェクトにレンダリングするライブラリ。スナップショットテストなどに使う。7で使うためのモジュール。現時点では必要だけど、その内いらなくなるであろう。7にネイティブ対応して、bridgeは不要になった。protected]^7.0.0-bridgeJestはv23.6.0が入った。scriptにjestを追加しておくといい。(後略)JestセットアップJestの設定ファイルであるjest.config.jsをプロジェクトルートに生成する。testing」にjsdomで答えるのがポイント。ブラウザで動かすアプリなので。origins」というエラーが出る問題があるので、testURLを「http://localhost/」に設定しておく必要がある。true,};また、例によって、(主にJestのグローバル変数のために、)JestのテストコードとESLintがけんかするので、ESLintをなだめるためにeslint-plugin-jestを入れる。};Jestのテスト作成Jestのテストは、jest.config.jsのtestMatchにマッチするJavaScriptファイルに書く。デフォルトでは__test__ディレクトリ以下に置けばいい。テストコードはよくある感じのBDD風に書けばいいと思う。});});スナップショットテストJestの目玉のひとつはスナップショットテスト。Reactコンポーネントのレンダリング結果が以前と変わってないかをテストできる。});});このテストの初回実行時には、src/__tests__/components/__snapshots__/HogeButton.test.jsx.snapというスナップショットファイルが生成される。これはテキスト形式で、以下のような人が読み解ける内容。/></button>`;スナップショットファイルはコミットしてバージョン管理して、変更があったときには差分を確認する。EnzymeReactのユニットテストをよりいい感じに書けるようにしてくれるユーティリティライブラリがEnzyme。Reactコンポーネントをレンダリングして、jQueryみたいなAPIでセレクタを指定したりしてエレメントを取得し、アサートするようなテストが書ける。Enzymeによるレンダリングには以下の3種類があり、テスト内容によって使い分ける。浅くレンダリングして、子コンポーネントに影響を受けないテストができる。Reactのライフサイクルメソッドも呼んでくれる。jsdomなどを使って完全なDOMツリーとしてレンダリングする。静的なHTMLに出力して、それをパースする。Enzymeはv3から本体とアダプタという構成になっていて、Reactのバージョンによってアダプタを使い分ける。(preactとかInfernoのアダプタもある。enzyme-adapter-react-16Enzymeはv3.7.0が入った。jest-enzymeも入れるとアサーションがいい感じに書けてよりいいかもしれない。Renderingをやってみる。ContainedButtonがクリックされたとき、onClickに指定した関数が呼ばれることを確認するテストは以下のように書ける。RenderingのAPIで、内部でreact-test-rendererを使っているみたいなんだけど、mountのためにreact-test-rendererをimportする必要はない。以上で全10回に渡るReact―Redux環境のセットアップ体験記が完結。予定だったけど、次回TypeScriptをやる。