Create React App のドキュメントを真面目に拾い読みしてみる

この記事は [React Advent Calendar 2019](https://qiita.com/advent-calendar/2019/react) の 17日目向けに書き下ろしたものです。

## この記事を書いた動機

[Create React App](https://create-react-app.dev/)（CRA）は Facebook の React 開発チームが推奨し同社が提供している、React アプリのプロジェクト雛形生成ツールです。React アプリ開発におけるデファクトスタンダードと言っていい存在で、[『りあクト！』シリーズ](https://oukayuka.booth.pm/)でも一貫して使われています。

create-react-app コマンドで生成したプロジェクトは同パッケージに含まれる react-scripts を使うことで複雑な Webpack 設定をいい感じに隠蔽してくれるため、Webpack 職人がチームにいなくても快適な DX を維持できます。

以前は create-react-app で生成したプロジェクト内の README にはその時点での最新の[公式ドキュメント](https://create-react-app.dev/docs/getting-started/)がまるごと含まれており、それはあたかも公式が「**（この長大なドキュメントを）読め！**」と強制しているかの如くでした。確かにその内容はよくできていて、開発途中でハマって検索した結果がすでに自分のアプリの README（＝公式ドキュメント）に書いてあったということが数しれずありました。

しかしいつからか create-react-app で生成された README には公式ドキュメントへのリンクだけが貼られることとなり、あの有用なドキュメントの存在感が薄れてきているように思います。かくいう自分もあれを最後まで目を通したことがなく、内容も随時アップデートされているはずなので、Advent Calendar に参加するという締め切り駆動でちゃんと読んでみて、その知見を忘れないよう残しておきたいと思いました。

以下、[2019年12月現在の Create React App 公式ドキュメント](https://create-react-app.dev/docs/getting-started/) に目を通した上で、個人的に「これ知らんかったわー」「自分的には知ってるけど、React 始めたばかりの人は見落としがちじゃね」と感じた部分をピックアップしたものです。

## プロジェクトテンプレート

create-react-app コマンドは --template オプションを指定することで、公式やサードパーティから提供されているテンプレートを下敷きにした形でプロジェクトを作成することができます。
公式が提供しているのは以下の二つ。

- [cra-template](https://github.com/facebook/create-react-app/tree/master/packages/cra-template)
- [cra-template-typescript](https://github.com/facebook/create-react-app/tree/master/packages/cra-template-typescript)

cra-template-typescript を使うことで TypeScript を使ったプロジェクトが作成できます。ちなみに、以下の三つの実行結果は同じです。

```
$ npx create-react-app my-app --template cra-template-typescript
$ npx create-react-app my-app --template typescript
$ npx create-react-app my-app --typescript
```

その他 [npm のサイトで「cra-template-*」と検索する](https://www.npmjs.com/search?q=cra-template-*)と、サードパーティが提供しているカスタムテンプレートを見つけることができます。
なお、[自分でカスタムテンプレートを作る](https://create-react-app.dev/docs/custom-templates/)ことは可能ですが、使用するには npm への publish が必要になります。そのため、お手製のカスタムテンプレートを社内で手軽に共有するといった使い方には向かないようです。残念。

👉 [参照元ページ](https://create-react-app.dev/docs/custom-templates/)

## バンドルサイズの解析
ビルドされた JavaScript ファイルの各パッケージのバンドルサイズを [source-map-explorer](https://github.com/danvk/source-map-explorer) を使うことで分析できます。同様のツールでは [Webpack Bundle Analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) のほうがメジャーで結果画面もカラフルでわかりやすいのですが、使うためにはプロジェクトを eject した上で `webpack.config.js` をいじる必要があるため、公式は source-map-explorer を推奨しているようです。

sourece-map-explorer を使うためにはインストールの必要すらなく、以下のコマンドを実行するだけでこんな感じのシンプルな解析結果がブラウザに表示されます。

```
$ npx source-map-explorer 'build/static/js/*.js'
```
![解析結果画面](https://raw.githubusercontent.com/danvk/source-map-explorer/HEAD/screenshot.png)
👉 [参照元ページ](https://create-react-app.dev/docs/analyzing-the-bundle-size/)


## HTTPS を開発環境で使う
プロジェクトルートで `yarn start` を実行すると http://localhost:3000/ でそのアプリが development として起動されますが、環境変数 `HTTPS=true` を設定することで https://localhost:3000/  の HTTPS プロトコルで起動されるようになります。

もちろん「localhost」には正式な証明書がないので以下のようなエラー画面が表示されますが、「詳細設定 ＞ localhost にアクセスする（安全ではありません）」でアクセスできます。

![privacy-error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3742/188e8a38-afc7-18b5-5954-71999ec1cba7.png)

なお、`package.json` に設定するには以下のように記述します。

```diff
   "scripts": {
-    "start": "react-scripts start",
+    "start": "HTTPS=true react-scripts start",
```

👉 [参照元ページ](https://create-react-app.dev/docs/using-https-in-development/)


## パブリックフォルダ

画像ファイルなどのアセットファイル群は `public/` フォルダに置くことでデプロイ、参照することができます。いっぽうで `import` を使えば Webpack の配下でビルドされたモジュール内に組み入れることも可能。後者のメリットとしては以下のものが挙げられます。

- スクリプトやスタイルシートの場合は minify されるのでバンドルサイズを減らすことができる
- ファイルがなかったりファイル名を間違えていた場合はコンパイルエラーが出るので、デプロイ前に気づくことができる
- ファイル名にビルドハッシュが付与されるので、ブラウザや CDN のキャッシュによるバージョン不整合が起きることがない

create-react-app がデフォルトで生成するアプリケーションでも、SVG ロゴファイルや CSS ファイルが `src/` 下に置かれ `import` 形式で組み込まれるいっぽう、PNG ロゴファイルや favicon ファイル、robots.txt や manifest.json などは `public/` フォルダに配置されています。どちらの形式を採用するかは、ファイルごとにその性質を考慮した上で決定しましょう。

なお `public/` フォルダに置いたファイルは `index.html` からは

```html
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
```

JavaScript（JSX）のコードからは

```jsx
<img src={process.env.PUBLIC_URL + '/images/logo512.png'} />
```

のように参照することができます。

👉 [参照元ページ](https://create-react-app.dev/docs/using-the-public-folder)


## カスタム環境変数

react-scripts には [dotenv](https://github.com/motdotla/dotenv) が含まれており、プロジェクトルートに `.env` ファイルを置けば自動的に読み込んでくれます。どの環境での実行時にどのファイルが読み込まれるのかは以下の通り。

- `.env` … 常に読み込まれる
- `.env.local`  … ローカル実行時、test 環境以外で読み込まれ、`.env` の設定を上書きする
-  `.env.development`, `.env.test`, `.env.production`  … それぞれ development 環境、test 環境、production 環境のみで読み込まれる
-  `.env.development.local`, `.env.test.local`, `.env.production.local`  … それぞれローカル実行時の development 環境、test 環境、production 環境のみで読み込まれ、上位の設定を上書きする 

**非常に重要な注意点**として、CRA の dotenv はカスタマイズされておりアプリから参照できる環境変数を設定するためには独自の命名規則があります。

```
REACT_APP_API_KEY=***************************
REACT_APP_AUTH_DOMAIN=mangarel.com
```

上記のように、変数名の頭には必ず **`REACT_APP_`** をつけること。
また、設定ファイルの中で他の環境変数を参照することもできます。

```
REACT_APP_MY_ENV=${NODE_ENV}
AWESOME_WORD=awesome
REACT_APP_AWESOME_DOMAIN=my.${AWESOME_WORD}.com
```

ちなみに、設定したカスタム環境変数は `public/index.html` からも以下のように参照することができます。

```html
<title>%REACT_APP_WEBSITE_NAME%</title>
```

👉 [参照元ページ](https://create-react-app.dev/docs/adding-custom-environment-variables)


## テストの実行

react-scripts にはもはやフロントエンドにおけるテストツールのデファクトスタンダードと言っていい [Jest](https://jestjs.io/) が含まれており、CRA で作成されたプロジェクトでは Jest を使ったテストがすぐ書けるようにお膳立てされています。雛形となる `src/App.test.tsx` が作られているので、それを拡張していけばいいでしょう。

react-scripts 経由のテスト実行では、下記の命名規則に従ったファイルを自動的にテストファイルとして認識します。

- 任意の `__tests__/` フォルダ内に置かれた JavaScript または TypeScript ファイル
- `.test.{js,jsx,ts,tsx}` という拡張子がついたファイル
- `.spec.{js,jsx,ts,tsx}` という拡張子がついたファイル

なお公式では、`src/utils/foo.js` に対して `src/utils/foo.test.js` のようにテストファイルを同階層に置くことを推奨しています。

`yarn test` を実行しておくと、ファイル保存時に差分変更のあったテストだけが実行されるので、開発時にはウォッチプロセスを起動したままにしておくと便利です。

また、VSCode を使っている人は [vscode-jest](https://github.com/jest-community/vscode-jest) 拡張をインストールしておくと、テストを書いているそばからエディタ内で実行結果がわかるので捗ります。

![vscode-jest.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3742/f3e7ed7d-0b27-fff4-1e4d-d0eb07771b37.png)

👉 [参照元ページ](https://create-react-app.dev/docs/running-tests/)


## ビルドされたモジュールをローカルサーバで実行する

Service Worker のデバッグ時など、ローカルでアプリを Webpack Dev Server で実行するのではなくビルドされたモジュールを Node サーバで実行したいときがあります。そのような場合は [serve](https://github.com/zeit/serve) を使いましょう。

```
$ npm install -g serve
$ serve -s build
```

なおデフォルトでは 5000 番ポートで起動して Firebase Emulator などとバッティングするので、`-l` オプションを使えばポート番号を任意に変更することができます。

```
serve -s build -l 4000
```

👉 [参照元ページ](https://create-react-app.dev/docs/deployment/)


## Eject 以外の方法

`yarn eject` を実行すると CRA の管轄から離れて Webpack の設定を自分で好きにいじれるようになります。しかしそれは茨の道なので、チーム全員が絶対に必要だという合意が取れない限りはやるべきではありません。

「どうしてもこの Webpack プラグインが使いたい！」といった場合には、公式ドキュメントでは言及されていませんが [react-app-rewired](https://github.com/timarney/react-app-rewired) というツールを使うことができるので、その採用を検討しましょう。

![trends-react-app-rewired.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3742/a7f6efdb-7964-0834-e74a-660978d75d7f.png)