ReactアプリをローンチするまでにCreateReactAppのドキュメントは読んでおくべき


概要

ReactアプリをFirebase Hosting(以降、FH)にデプロイしたのですが、しばらくソースコードが公開状態でしたorz
CreateReactApp(以降、CRA)のドキュメントを見ていればこんなことやらずに済んだのに・・・という失敗談です。
もう一つは、CRAとPWAとFHの組み合わせで設定しておくべきことを、ドキュメントに沿って設定します。

読者対象

  • ReactアプリをCRAのドキュメント読まずにローンチしようとしている方。
  • PWAのReactアプリをFHにデプロイしようとしている方。

トラブルと対策

どうしてYouはソースをぶちまけてしまったのか?

CRAを使うと、npm run buildを実行すればデプロイするためのファイルができてしまいます。
開発者が迷わなくていいように、賢人たちが導いてくれます。
だがしかし、ちょっと注意すべき点があります。
buildフォルダを丸ごと本番環境に展開すると・・・ブラウザの開発者ツールのsourceでソースファイルがすべて見れてしまいます
しかも、コメントまで見れちゃうので、感情ぶちまけたコメントなんて書いてた日には・・・

どうしてこんなことが起こるかというと、公式ドキュメントのオプションでGENERATE_SOURCEMAPというのがあって、これがONになっています。
オプション名の通りソースマップ(ビルドでminifyされたソースを元のソースに再構成できるファイル)を生成しているからです。
build/static/jsフォルダを見ると、ソースファイルのjsとセットで.mapファイルがあると思います。

対策としては、GENERATE_SOURCEMAPをOFFにして生成しないか、デプロイ対象から外せばOK。
FHの場合の設定はこうなります。
ignoreの最後に"**/*.map"を追加し、任意のフォルダにあるmapファイルをデプロイ対象外に指定。

firebase.json
{
  "hosting": {
    "public": "build",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**",
      "**/*.map" // <=追加
    ],
    ...
  }
}

これでソースは守られた(;^_^A

FHでService Worker(以降、SW)を使うなら一つだけやらなければならないことがある

次はFHでPWA化のためSWを有効化する場合の注意点です。
SWはオフライン対応やキャッシュ等の強力な機能を提供します。
しかし、キャッシュにおいてはしっかり理解して利用しないと、更新したのに更新されないとはまることになりますorz
そんな経緯があってデフォルトではOFFになっていること、有効にする場合、アドバイス等が公式ドキュメントに書かれています。
SW使うなら絶対に読んでおくべきです。
https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app

そして、FHにデプロイする場合、firebase.jsonにキャッシュ設定を追加すること!という注意が公式ドキュメントにあります。
その他、サーバーやサービスでのデプロイについても書かれているので必見です。
https://facebook.github.io/create-react-app/docs/deployment#firebase-https-firebasegooglecom

firebase.json
{
 "hosting": {
   ...
   "headers": [
     {"source": "/service-worker.js", "headers": [{"key": "Cache-Control", "value": "no-cache"}]}
   ]
   ...

no-cacheはキャッシュしないと一見取れますし、更にMDNの日本語訳がおかしいと二重苦ですが、キャッシュを使う前にサーバーに確認に行くことを意味するようです。
つまり、更新があった場合サーバーから更新されたservice-worker.jsを取得するため、問題なく更新されます。(デフォルトだと一旦タブを閉じないと更新待機で古いSWで動きますが)
もし、FHにこの設定をしなかった場合、更新されたことを知らずにキャッシュしたservice-worker.js利用するため、更新が反映されずドはまりするということになりそうです
FHはデフォルトだと1時間のキャッシュ、SWは仕様で24時間経過後はいったんサーバーにチェックするということなので、無限ではなさそうですが・・・。
更新されてないんだけどと問い合わせが来て、キャッシュをクリアして、開きなおして、いったん閉じて再度開きなおしてください・・・つらいな( ´ー`)y-~~

CRAが指南するもう一歩先に進めるキャッシュ設定

公式ドキュメントでは、staticフォルダ配下のファイルはキャッシュ期間を大幅に引き延ばすのがベストプラクティスと言っています。
https://facebook.github.io/create-react-app/docs/production-build#static-file-caching
ファイル名にハッシュ値が含まれているため、ファイル名が同じで内容が異なることはないという話ですね。
FHだとデフォルト1時間しかキャッシュしないため、更新頻度が長ければ長いほど無駄なリクエストが生じます。
ということで、これをFHで設定するならこうなります。

firebase.json
{
  "hosting": {
    ...
    "headers": [
      ...,
      {
        "source": "/static/js/*",
        "headers": [{"key": "Cache-Control", "value": "max-age=31536000, immutable"}] // <=追加
      }
    ]
  }
}

.max-age=31536000はドキュメント通り1年と大幅に引き延ばします。
ドキュメントにないimmutableですが、これは私オリジナルで、MDNのCache-Controlの記述がもとになっています。
どうもリロード等では、有効期間内でも更新のリクエストが発生するようで、その問い合わせを抑止するためのオプションとのこと。
max-ageでも十分ですが、切り詰めたい方はご参考に(;^_^A

まとめ

ドキュメント読まずに進める私ですが、CRAドキュメントはそれを改めるには十分でした。
特にSWのキャッシュ設定しなかったら、しばらくパニックになっていたことは間違いない(;^ω^)
ドキュメントの量が多いと消耗して諦めますが、とりあえず大まかな内容だけ把握するといいかもしれないと思いました。
FHの場合はinitの選択肢に何を選ぶかまよいましたが、CRAドキュメントにそういえばデプロイのことあったと思いだしたら、あとはすいすい。

いろいろ書きましたが、誰かのソース公開の危機を救えたらそれ幸いm(__)m