為什麼我要用 PWA

我最近在寫一個 side project:喝喝,一個記錄喝水狀況並和其他人分享的網站(aka 一個只能拿來喝水的社群媒體)。我打算在裡面使用各種我沒用過的工具,順便學習怎麼用一些平常寫專案不會接觸到的技術、純粹因為自己想要就加上去。

PWA 是其中一個我想要加入的東西,因為它讓網頁可以像應用程式一樣被下載,提供更原生、流暢的體驗,不需要多一個打開瀏覽器的步驟。

幫我的 React 專案加上 PWA

我的 React 是使用 Vite 當作開發環境,所以我選擇用 Vite PWA 這個套件幫 React 加上 PWA,只需要

  1. 建立 favicon 檔案(我用的工具)、放到 static/ (要注意 manifest 要使用工具生成的或是套件生成的)
  2. vite.config.ts 加上
{
  plugins: [react(), VitePWA({
    registerType: 'autoUpdate',
    injectRegister: 'auto',
    includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'mask-icon.svg'],
    manifest: {
      name: "喝喝",
      short_name: '喝喝',
      description: "An application for tracking drinking water, and share progress with your friends",
      theme_color: '#ffffff',
      icons: [
        {
          src: 'pwa-192x192.png',
          sizes: '192x192',
          type: 'image/png'
        },
        {
          src: 'pwa-512x512.png',
          sizes: '512x512',
          type: 'image/png'
        },
        {
          src: 'pwa-512x512.png',
          sizes: '512x512',
          type: 'image/png',
          purpose: 'any'
        },
        {
          src: 'pwa-maskable-512x512.png',
          sizes: '512x512',
          type: 'image/png',
          purpose: 'maskable'
        }
      ]
    }
  })],
}

就可以讓網頁安裝在裝置上了,這個插件會自動生成對應的 manifest.webmanifestsw.js,讓網站符合 PWA 的規範

至於開發則有一些事情要注意,像是 dev 模式下是不會有 PWA 的功能,要測試需要使用 vite preview,也就是在本地預覽 production 模式。如果要測試 Android 的狀況,可以用 Chrome 的 Remote Debug 功能、在自己的手機上測試電腦上運行的 localhost 網頁

要測試自己的網站有沒有符合 PWA,可以打開 Chrome 開發者工具的 Application 頁面,點開 Manifest 和 Service workers 兩個部分、看看有沒有錯誤訊息

網站怎麼不會更新

在網頁可以安裝以後,我就以為沒有問題了,但是我在後來開發時發現了一個問題,那就是用不同裝置看到的網站版本不一樣。經過研究以後,發現是 Service Worker 並未正確註冊,導致即使設定了registerType 為 ‘autoUpdate’, Service Worker 也無法觸發更新、刷新頁面成新的版本

幫套件註冊 Service Worker 的方法就是在 main.tsx 加上

import { registerSW } from "virtual:pwa-register";

registerSW({ immediate: true });

這算是我沒有把文件完全看完的問題。不過,了解 PWA 的原理會比較好理解為什麼這件事情會發生

Vite PWA 官方文件(自動更新)

PWA 原理

PWA 的底層由兩個部分組成:Service Worker 和 Manifest

  • Service Worker:在背景快取網頁資源、讓網頁可以在後臺運行,提供離線訪問、推送通知等功能
  • Manifest:定義不同平臺的 icon 要使用那個檔案、名稱、用什麼模式

PWA 決定什麼時候要更新網頁或是使用快取有幾種機制,瀏覽器會先使用快取的檔案,再檢查是否有新版本的 Service Worker,如果有的話就會更新。在 PWA 中,當檢測到新版本時,提供更新給用戶的方式主要有兩種:

  • 自動更新:頁面會直接刷新並加載新版本,但這可能導致正在進行的操作被中斷、資料丟失。
  • 詢問用戶是否更新:會彈出提示詢問用戶是否刷新頁面以更新版本,缺點是可能造成不同用戶間版本不一致

我在知道了套件背後在做的事情以後,就能對於 debug 比較有方向,知道應該去查 Service Worker 以及更新機制的部份。

結論

雖然套件可以抽象化最底層的 API,讓實現基本的需求變得簡單,但是要使用更進階的功能還是需要了解技術具體的規格、如何實現,才能真正的掌握一項技術,甚至於不需要依靠套件也能自己實現功能