create-react-app で作成したReactのプロジェクトに「後付けで」PWA化する(Workbox使用)


TL;DR

  • create-react-app のPWAテンプレートなしプロジェクト
  • eject なし
  • Webpackの設定オーバーライドなし

でWorkboxを導入してPWAを有効にできる。

はじめに

create-react-app でPWA対応のReactプロジェクトを作るには --template cra-template-pwa というオプションでPWA対応のテンプレートを読み込む方法が見つかります。

しかし、プロジェクトの立ち上げから携わることができないケースもあります。その場合PWA対応のテンプレートを使わなかった状態から「後ほどPWA対応にする方法を探す」としても見つかりづらかったです(2021/08/18現在)

また、 create-react-app で作成したプロジェクトは eject コマンドを使って設定ファイルを抽出しないとWebpackの設定を変更するのが難しくなります。一度ejectするとその前の状態に戻せないのでejectを選択しない場合もあります。
ejectせずにWebpackの設定をオーバーライドする方法(react-app-rewiredなど)を試しましたが正しく設定することができませんでした。

そこで、PWA未対応のReactプロジェクトに導入する方法としてWorkboxをインストールする方法が正しく動作したので、導入手順を残そうと思います。

環境

$ node --version
v14.17.3

$ npm --version
6.14.13

$ yarn --version
1.22.11

Workbox パッケージのインストール

workbox wizard を使ってWorkboxに必要なファイルを生成します。使うのはこの1回限りになりますが、 npx が使えないためworkbox-cliをグローバルでインストールする必要があります。

npm i -g workbox-cli

次に、Reactのプロジェクトディレクトリ内でwizardを実行します。

workbox wizard

いくつか質問があるので答えていきます。

? What is the root of your web app (i.e. which directory do you deploy)?

そのうち、Workboxが生成するService Workerの出力先を尋ねられます。 ここではpublic を選択します。

「デプロイ先」ということで build を選択しそうですが、これではReactが読み込んでくれないので public に設定します。

この設定にするとdevelopmentビルドで確認することができ、productionビルドの場合はあとで yarn build コマンドを実行すると build にService Workerのファイルも配置されます。

そのほかのオプションは特に変更しません。

$ workbox wizard
? What is the root of your web app (i.e. which directory do you deploy)? public/
? Which file types would you like to precache? ico, html, png, json, txt
? Where would you like your service worker file to be saved? public/sw.js
? Where would you like to save these configuration options? workbox-config.js
? Does your web app manifest include search parameter(s) in the 'start_url', other than 'utm_' or 'fbclid' (like '?source=pwa')? No
To build your service worker, run

  workbox generateSW workbox-config.js

as part of a build process. See https://goo.gl/fdTQBf for details.
You can further customize your service worker by making changes to workbox-config.js. See https://goo.gl/gVo87N for details.

Workboxのインストール(プロジェクト, devDependencies)

workbox wizard で生成したWorkboxの設定ファイルからService Workerを生成するにはプロジェクト側にWorkboxを導入します。

PWA対応のテンプレートを使ったReactプロジェクト (--template cra-template-pwa オプションありでプロジェクトを立ち上げた場合)を参考にしています。不要なパッケージがあるかもしれません。

$ yarn add -D workbox-background-sync workbox-broadcast-update workbox-cacheable-response workbox-core workbox-expiration workbox-google-analytics workbox-navigation-preload workbox-precaching workbox-range-requests workbox-routing workbox-strategies workbox-streams

serviceWorkerRegistration.js の移植

PWA対応のテンプレートを使ったReactプロジェクトにある serviceWorkerRegistration.jssrc ディレクトリに配置します。

Service Workerの設定

serviceWorkerRegistration.js で読み込むService Workerのファイル名が異なるのでここで変更します。

src/serviceWorkerRegistration.js
    window.addEventListener('load', () => {
      const swUrl = `${process.env.PUBLIC_URL}/sw.js`;

index.jsserviceWorkerRegistration.js を読み込んでService Workerをregisterするように設定します。

先頭にファイルを読み込むコードを追加します。

src/index.js
import * as serviceWorkerRegistration from './serviceWorkerRegistration';

読み込んだ serviceWorkerRegistration.js を使ってService Workerを登録するように次のコードを末尾に追加します。

src/index.js
serviceWorkerRegistration.register();

Service Workerの生成

こちらはWorkboxのコマンドを用います。 デフォルトではソースマップも出力されるため 設定を変更するなどでproductionビルドに混入しないよう注意する必要があります(回避方法は未確認)

$ workbox generateSW workbox-config.js

動作確認(localhostで可能)

serviceWorkerRegistration.js はデフォルトでdevelopmentビルドのPWAを無効にする設定があるため、developmentで確認したい場合はそれを外します。
productionコードであるかどうかの条件分岐があるのでそこを外します。

src/serviceWorkerRegistration.js(変更前)
export function register(config) {
  if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
src/serviceWorkerRegistration.js(変更後)
export function register(config) {
  if ('serviceWorker' in navigator) {

そして、devサーバーを起動してブラウザで開発者ツールを開き、ApplicationのService Workersか、LighthouseでProgressive Web Appのチェックを入れて確認できます。

$ yarn start

PWAになりましたね!
本記事ではPWA化までを説明したので、この後は足りない部分を修正したり、実際にホスティングサービスへ公開したりしましょう。

参考

create-react-appで作ったReact SPAにWorkbox-CLIでService Workerをねじ込む | WP Kyoto
https://wp-kyoto.net/replace-workbox-cli-into-create-react-app-app/