隨機手札 雜七雜八之地

Nuxt3中使用vite-pwa實現pwa功能

6 min前端筆記
#nuxt #nuxt3 #vue #pwa #vite-pwa

之前在 Nuxt2 時可以滿無痛的使用 nuxt/pwa 來為網站新增 PWA 功能,但因為此模組沒有開發 Nuxt3 版本,最近開始接觸 Nuxt3 後得尋找替代品,在官方模組清單頁面中搜尋 pwa 只發現一個模組:vite-pwa-nuxt。

關於 PWA,可參考 MDN 文件

雖然號稱是「Zero-config」 PWA Plugin for Nuxt 3 ,但實際套用之後發現還是要做一些設定,而且這個模組的文件……真的有點混亂,所以就寫這篇文章紀錄一下。


安裝與基本設定

如模組的名稱所示,這個模組只能跟 vite 一起使用,若是使用 webpack 就要找其他解決方案了。首先是安裝,這邊我使用 npm。

npm install -D @vite-pwa/nuxt

接著引用模組,這個跟其他 Nuxt3 模組差不多。然後根據官方文件填上一些需要的基本值。

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@vite-pwa/nuxt'],
  pwa: {
    // 設定是否有更新時自動更新,因為我的網站只是單純展示用,直接設定autoUpdate。
    registerType: 'autoUpdate',
    // 設定是否要在開發的時候(npm run dev)啟用pwa功能,為了方便測試,我是把他開啟。
    devOptions: {
      enabled: true,
    },
    // pwa的描述檔
    manifest: {
      name: '網站名稱',
      short_name: '網站名稱',
      description: '網站描述',
      lang: 'zh-Hant-TW',
      theme_color: '#000000',
    },
  },
})

ICON 設定

之後一些設定都會用到 icon,所以先來設定。

之前 Nuxt2 的 nuxt/pwa 模組可以在編譯時從一張源圖自動產生 pwa 所有需要的 icon,但 vite-pwa 需要先自己手動產生(或是把產生的部份寫成程式整合到編譯流程)。先用 npm 安裝官方提供的 icon 產生工具

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

接著把指令放到 package.json 中,這裡使用模組內建的minimal-2023設定值來產生 icon 圖組。

{
  "scripts": {
    // 這裡的public/icon.png要改成源圖路徑
    "generate-pwa-assets": "pwa-assets-generator --preset minimal-2023 public/icon.png"
  }
}

額外設定值(選擇性)

因為官方的 icon 產生工具在產生時會給 icon 一個 padding,產生出來的圖會有白邊(猜測是預防在各種圖案形狀時被截掉),覺得很醜,決定額外設定為 0。首先在專案的根目錄新增pwa-assets.config.ts檔案:

pwa-assets.config.ts
import {
  defineConfig,
  minimal2023Preset as preset,
} from '@vite-pwa/assets-generator/config'

// 把設定值的icon padding都設為0
preset.apple.padding = 0
preset.maskable.padding = 0
preset.transparent.padding = 0

export default defineConfig({
  preset,
})

執行指令

準備好源圖放在對應的路徑之後,就可以執行指令:

npm run generate-pwa-assets

執行完之後會印出 icon 的設定,再把他複製過去nuxt.config.ts裡面。

nuxt.config.ts
export default defineNuxtConfig({
  pwa: {
    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',
      },
    ],
  },
  modules: ['@vite-pwa/nuxt'],
})

icon 的部份就完成囉。


META 設定

根據官方文件所述,PWA 的基本需求需要在網站首頁有以下meta標籤:

<head>
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>My Awesome App</title>
  <meta name="description" content="My Awesome App description" />
  <link rel="icon" href="/favicon.ico" />
  <link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180" />
  <link rel="mask-icon" href="/mask-icon.svg" color="#FFFFFF" />
  <meta name="theme-color" content="#ffffff" />
</head>

因此要新增對應的 meta 設定,這邊設定在nuxt.config.ts中:

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      title: '網站名稱',
      viewport: 'width=device-width, initial-scale=1.0',
      meta: [
        { name: '網站描述', content: '網站描述' },
        {
          name: 'theme-color',
          content: '#ffffff',
        },
      ],
      link: [
        {
          rel: 'icon',
          href: `/favicon.ico`,
        },
        {
          rel: 'apple-touch-icon',
          // 這裡使用前一段@vite-pwa/assets-generator產生出來的圖片路徑
          href: `/pwa-192x192.png`,
        },
        {
          rel: 'mask-icon',
          // 這裡使用前一段@vite-pwa/assets-generator產生出來的圖片路徑
          href: `/maskable-icon-512x512.png`,
          content: '#ffffff',
        },
      ],
    },
  },
})

在根層級引入 vite-pwa 的 manifest 元件

最後一步就是在根層級(例如app.vue或是全域使用的layouts/default.vue)引入<VitePwaManifest />或是<NuxtPwaManifest />。我是放在app.vue

app.vue
<template>
  <VitePwaManifest />
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

這樣就大功告成囉,可以試試看npm run dev,看看 Chrome 有沒有出現「安裝」圖示,有的話就代表設定成功。


後記

不知道為什麼,Nuxt3 的模組只要是非官方開發的,文件的複雜度感覺都升了一個層級……,想到這部落格也要找時間升上 Nuxt3 就覺得頭很痛啊。


Support me on Ko-fi