Next.js で作成した Web アプリを PWA 対応する

Next.js で作成した Web アプリを next-pwa を使って PWA 対応してみました。複雑なキャッシュ戦略が必要でなければほとんどデフォルト設定のままでも問題なさそうです。
2021.06.27

経緯

趣味が手芸(ミシン)の妻からある日突然、slack でこんな画像が送信されてきました。

特に難しいものではなかったので、隙間時間でサッと作って Cloudflare Pages にデプロイしました。

計算したログを残せたほうがいいんじゃないか、そのログから合計をだしたりできたほうがいいのではないかなど色々と提案してみたのですが、これくらいシンプルなほうが使い勝手がいいとのことだったので希望通りに実装しました。

結果そこそこの反響があり、せっかくなのでオフラインでも動作するように PWA 対応をしてみました。

Next.js で PWA 対応

対応前のコードは上記になります。

ここでは Next.js の公式サイトにあるサンプルを参考に、next-pwa を使って PWA 対応していきます。

1. next.config.js

// /next.config.js
/** @type {import('next/dist/next-server/server/config-shared').NextConfig} */

const withPWA = require("next-pwa");
const runtimeCaching = require("next-pwa/cache");

const config = {
  pwa: {
    dest: "public",
    runtimeCaching,
  },
};

module.exports = withPWA(config);

runtimeCaching ではキャッシュ戦略の設定ができます。ここではサンプルと同じく、用意されている基本的な設定をそのまま使っています。

このアプリでは Google Fonts を使っていますが、上記の設定にはすでに 365 日 キャッシュする設定が含まれていました。

2. pages/_offline.tsx

今回作成したツールは、オンライン環境でのページを個別に用意する必要はありません。そのため、フォールバックのページである _offline.tsx はオンライン時のエントリポイントとなる index.tsx と同等の内容でにしました。

// /pages/_offline.tsx
import Page from ".";

export default Page;

3. manifest.webmanifest (manifest.json)

ウェブアプリマニフェストについては上記ページをご参照ください。manifest.json generator などで検索すると生成するアプリなどが見つかるはずです。

{
  "theme_color": "#f9a8d4",
  "background_color": "#fde68a",
  "display": "standalone",
  "scope": "/",
  "start_url": "/?source=pwa",
  "name": "Cloth Price Calculator",
  "short_name": "Cloth Price Calculator",
  "description": "生地のサイズから原価を計算するアプリ。",
  "icons": [
    {
      "src": "/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icon-256x256.png",
      "sizes": "256x256",
      "type": "image/png"
    },
    {
      "src": "/icon-384x384.png",
      "sizes": "384x384",
      "type": "image/png"
    },
    {
      "src": "/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ]
}

start_url にクエリパラメータを付与しているのは、PWA からのアクセスを Google Analytics で測定するためです。

設定した Manifest は DevTools の Application で確認できます。

4. src/pages/_app.tsx

// /pages/_app.tsx
<Head>
  <meta name="theme-color" content="#f9a8d4" />
  <link rel="manifest" href="/manifest.webmanifest" />
  <link rel="apple-touch-icon" href="/icon-192x192.png" />
</Head>

manifest を設定し、残りのいくつか必須の項目を追加します。

以上で PWA 対応が完了です。一度ビルドをすると、public/workbox**public/sw** が追加されると同時に、.gitignore にそれらのファイルの指定が追加されます。

Lighthouse で確認

ただしく設定できているかは DevTools の Lighthouse で確認できます。

Generate repost をクリックすると、次のように結果が表示されます。

ただしく設定できていない場合には、修正しておきしましょう。

iOS の実機で確認

iOS の実機で確認してみます。 Chrome は対応していないため、Safari でのみ確認します。

赤線で囲われているアイコンをタップします。

Sheets にある「ホーム画面に追加」をタップします。

画面の右上にある「追加」を選択すると、ホーム画面に追加されているはずです。

一度アプリを起動して表示したあと、オフライン状態でもアプリが問題なく使用できることが確認できると思います。

まとめ

Next.js での PWA 対応では next-pwa を使うととても簡単に対応することができます。複雑なキャッシュ戦略が必要でなければほとんどデフォルト設定のままでも問題なさそうでした。