為什麼我要用 PWA
我最近在寫一個 side project:喝喝,一個記錄喝水狀況並和其他人分享的網站(aka 一個只能拿來喝水的社群媒體)。我打算在裡面使用各種我沒用過的工具,順便學習怎麼用一些平常寫專案不會接觸到的技術、純粹因為自己想要就加上去。
PWA 是其中一個我想要加入的東西,因為它讓網頁可以像應用程式一樣被下載,提供更原生、流暢的體驗,不需要多一個打開瀏覽器的步驟。
幫我的 React 專案加上 PWA
我的 React 是使用 Vite 當作開發環境,所以我選擇用 Vite PWA 這個套件幫 React 加上 PWA,只需要
- 建立 favicon 檔案(我用的工具)、放到
static/(要注意 manifest 要使用工具生成的或是套件生成的) - 在
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.webmanifest、sw.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 的原理會比較好理解為什麼這件事情會發生
PWA 原理
PWA 的底層由兩個部分組成:Service Worker 和 Manifest
- Service Worker:在背景快取網頁資源、讓網頁可以在後臺運行,提供離線訪問、推送通知等功能
- Manifest:定義不同平臺的 icon 要使用那個檔案、名稱、用什麼模式
PWA 決定什麼時候要更新網頁或是使用快取有幾種機制,瀏覽器會先使用快取的檔案,再檢查是否有新版本的 Service Worker,如果有的話就會更新。在 PWA 中,當檢測到新版本時,提供更新給用戶的方式主要有兩種:
- 自動更新:頁面會直接刷新並加載新版本,但這可能導致正在進行的操作被中斷、資料丟失。
- 詢問用戶是否更新:會彈出提示詢問用戶是否刷新頁面以更新版本,缺點是可能造成不同用戶間版本不一致
我在知道了套件背後在做的事情以後,就能對於 debug 比較有方向,知道應該去查 Service Worker 以及更新機制的部份。
結論
雖然套件可以抽象化最底層的 API,讓實現基本的需求變得簡單,但是要使用更進階的功能還是需要了解技術具體的規格、如何實現,才能真正的掌握一項技術,甚至於不需要依靠套件也能自己實現功能