😀

Nuxt3をPWA化する

2024/01/24に公開

Nuxt3をPWA化する

WEBアプリをネイティブアプリライクに活用できるPWAは非常に便利です。
賛否両論あるかとは思いますが、私はPWAを推しています。
さて、そのPWAですが、現在Nuxt周りの環境がどんどん更新されていることもあり、また、一番主流のライブラリがインストールすればすぐ動く、という状態ではないため、現状で動作させるための手順をまとめたいと思います。

環境

Windowsで開発、Vercelにデプロイして検証してます。
動作はAndroidのGoogle Chromeで確認してます。

"nuxt": "^3.9.3",
"@vite-pwa/assets-generator": "^0.2.3",
"@vite-pwa/nuxt": "^0.4.0",

SSRでもSPAでも動作したと思います。

ライブラリの選定

Nuxt2時代の「nuxt/pwa」がNuxt3に対応しておりません。
そこで公式を目指して「nuxt-pwa-module」が誕生しましたが、
現状「vite-pwa/nuxt」が最も主流で有力となっているようですので、今回はこの「vite-pwa/nuxt」を使用します。

「vite-pwa/nuxt」の使い方

インストールは公式に書いてある通りですが以下のように行います。

npm install -D @vite-pwa/nuxt

アセットジェネレータ

さて、次にアイコンを用意します。faviconジェネレータなどもありますが、画像から自動でアイコン群を作成してくれる公式のアセットジェネレータがありますので今回はそちらを使用します。必須ではありません。
なおこちらを使用した場合、元画像に背景がある場合に、背景の周りに透明色、又は白色の縁取りが自動で作成されますので気を付けてください。

npm install -D @vite-pwa/assets-generator

インストールしたらパッケージに以下のようなスクリプトを用意して実行します。
「public/icon.png」の箇所はアイコンに使用する画像へのパスを記載してください。
なお、このアイコンは512x512以上が推奨されます。
また、可能であればSVGで用意しましょう。

"scripts": {
  "generate-pwa-assets": "pwa-assets-generator --preset minimal-2023 public/icon.png"
}

こちらを実行すると「public」下に各種画像が作成され、以下のような内容がCLIに表示されると思います。こちらは後ほど使用します。

<link rel="icon" href="/favicon.ico" sizes="48x48">
<link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png">

{
  "icons": [
    {
      "src": "pwa-64x64.png",
      "sizes": "64x64",
      "type": "image/png"
    },
    {
      "src": "pwa-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "pwa-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    },
    {
      "src": "maskable-icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

「nuxt.config.ts」の設定

これで動けば万々歳なのですが、ことはそう簡単ではありません。
「nuxt.config.ts」を設定します。

以下のサイトが参考になるかと思いますが、そのままでは不都合もありますので、本記事を参考にされるのが良いと思います。
https://qiita.com/umiremix/items/c8d5925d88ddc9f6e9bf

export default defineNuxtConfig({
    app: {
        head: {
            meta: [
                {name: "theme-color", content: "#326CB3"},
            ],
            link: [
                {rel: 'icon', href: `/favicon.ico`, sizes: "48x48"},
                {rel: 'apple-touch-icon', href: `/apple-touch-icon-180x180.png`},
            ],
        },
    },
    modules: ['@vite-pwa/nuxt'],
    pwa: {
        registerType: "autoUpdate", // 多分なくてもよい
        manifest: {
            name: 'アプリ名',
            description: "アプリ説明",
            theme_color: "#326CB3", // テーマカラー
            lang: "ja",
            short_name: "アプリ短縮名",
            start_url: "/",
            display: "standalone",
            background_color: "#ffffff",
            icons: [
                {
                    "src": "pwa-64x64.png",
                    "sizes": "64x64",
                    "type": "image/png"
                },
                {
                    "src": "pwa-192x192.png",
                    "sizes": "192x192",
                    "type": "image/png"
                },
                {
                    "src": "pwa-512x512.png",
                    "sizes": "512x512",
                    "type": "image/png"
                },
                {
                    "src": "maskable-icon-512x512.png",
                    "sizes": "512x512",
                    "type": "image/png",
                    "purpose": "maskable"
                }
            ],
        },
        workbox: { // なんか必要
            navigateFallback: null
        },
        devOptions: { // テスト用
            enabled: true,
            type: "module"
        },
    },
})

さて、以下はまるでNuxt2時代の記述ですが、公式がそう書けと言っているので書きます。

modules: ['@vite-pwa/nuxt']

そしてマニフェストの情報を記載します。マニフェストの内容は各アプリに合わせて書き換えてください。
「icons」については「アセットジェネレータ」を使用した場合は、CLIに表示された「icons」部分をそのまま記入してください。自作の場合は適宜変更してください。
「meta」の「theme-color」ですが、こちらは記載しないと「Lighthouse」で確認した際に怒られます。どうも自分で記載しないと追加されないようです。
「link」部分は「アセットジェネレータ」を使用した場合は、CLIに表示された「link」の内容をNuxtの形に合わせて記述します。

「registerType: "autoUpdate"」の項ですが、これがあるとアプリに更新があった場合に自動でリロードしてくれるようです。結構便利だなと思いますが、これがあるとAndroidで「アプリをインストールしますか?」の画面をあまり出してくれなくなるように思います。

「devOptions」ですが、こちらはテスト環境でPWAを実行したい場合には記載が必要です。本番環境で動けばいい場合は不要と思います。

「workbox」の項ですが、なんかこれがないとインストールを進める表示がなされない気がします。検証が必要です。

また、先の参考にあげたページでは「client: {installPrompt: true,}」などの記載がありますが、この辺りは設定しないほうが無難と思います。恐らくインストールを促す画面等の設定と思いますが、下手に設定するとGoogleに怒られます。

加えて、先の参考ページでは「nuxt.config.ts」に「 { rel: "manifest", href: "/manifest.webmanifest" }」の記載をしていますが、こちらは以下の公式の方法で対応します。

「app.js」等の設定

上記「manifest.webmanifest」へのリンクを設定する方法として以下のように例えば「app.js」に「<NuxtPwaManifest />」を記載します。
これにより、当該ページに「<link rel="manifest" href="/manifest.webmanifest">」が挿入されるようになります。

<template>
  <NuxtPwaManifest />
  <NuxtPage />
</template>

完成

恐らくこれで完了と思います。
PWAはちょっとした違いでインストールできなかったり、インストールを進める画面が出なかったり、なーんか微妙な挙動が多い気がしますが。
取り合えず私の環境ではこれで動作しました。

Discussion