PWA
Progressive Web Apps (PWAs)
2020/12/29
2021/08/01 (新增內容)
2021/12/14 (更新內容)
簡介
越來越多的公司希望能讓現在的web應用程式能直接用在App上,首先,要採用Responsive Web Design (RWD)的概念開發web應用程式,讓web應用程式可以依據螢幕的大小進行調整。雖然這樣就可以在手機上使用web應用程式,可是還有一些問題:
離線使用: 一般的手機App是安裝在手機上,即使網路斷線,還是可以使用,傳統的網頁是在伺服器上產生網頁內容,只要斷線就沒辦法看到網頁。
使用手機上的資源: 過去因為手機App是安裝在手機上,所以,可以直接使用手機上的資源,網頁因為資訊安全的因素,無法取得手機上的資源,然而,最近web browser可以取得手機的資源越來越豐富 (參考: What Web Can Do Today? ),可以從你的手機打開這個網頁,就可以知道你的手機上目前所使用的瀏覽器可以支援那些功能。
設定
使用react的好處之一是可以透過create-react-app產生一個PWA
service worker需要https (localhost除外),比較簡單的方式就是發佈到github pages或gitlab pages。
service worker需要在production的環境下 (npm run build),比較簡單的方式就是發佈到github pages或gitlab pages。
[Day 30 - 臺灣好天氣] 發布上 Github Pages 不夠,還要變成手機 App!還有那些重要但故意先不告訴你的內容 (2019)
在First React ,我們建議大家使用pwa的樣板
npx create-react-app . --use-npm --template cra-template-pwa
如果要將既有專案轉成PWA專案:
create-react-app的template比較完整,如果一開始的時候沒有使用pwa的樣板,可以到這裡下載所需要的檔案:
create-react-app會提供PWA的樣板,所以,在index.js裡會有:
serviceWorkerRegistration.unregister();
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://cra.link/PWA
serviceWorkerRegistration.unregister();
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
要啟動PWA,只要把這一行改為:
serviceWorkerRegistration.register();
如果沒有這一行,就麻煩加上這一行,並且,記得要import。
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
//不是 import serviceWorkerRegistration from './serviceWorkerRegistration';
serviceWorkerRegistration.register();
並到cra-template-pwa下載
serviceWorkerRegistration.js
service-worker.js
並且放在src下。
這樣就已經可以讓我們的app可以離線了!
不過,為什麼老師不是第一週就請大家改這一行? 因為,改了之後,會增加開發及除錯的困擾,因為,瀏覽器會將內容cache,程式改好之後的結果不會馬上可以看到,還必須先清除瀏覽器上的cache。
來介紹一下PWA的一些基本要件,首先,要有個manifest.json,create-react-app已經幫我們產生了一個manifest.json,manifest.json的用途在於當我們把網頁加到手機的主畫面時,所應該使用的名稱、ICON及其他設定。(詳參: Add a web app manifest )
public/manifest.json
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
除此之外,create-react-app也幫我們產生了一些所需要的js檔,如: src/service-worker.js、src/serviceWorkerRegistration.js
啟動PWA
打開chrome,開啟「開發人員工具」,點選「Application」,可以看到在「Manifest」下可以看到manifest.json裡的設定。在「Service Worker」下,會看不到任何service worker正常執行中。
因為service worker必須在production環境下,所以,接下來,必須build我們的react專案
npm run build
build完,先安裝serve
npm install -g serve
就可以執行build的結果了
serve -s build
注意,執行的port從原本的3000改成5000。
打開chrome,可以發現多了一個「安裝Create React App Sample」(如果只是執行 npm run start,是無法安裝的)。
開啟「開發人員工具」,點選「Application」,可以看到在「Manifest」下可以看到manifest.json裡的設定。在「Service Worker」下,也看到service worker正常執行中。
如果service worker無法執行,請檢查一下package.json,暫時把homepage改回「.」,因為我們現在是佈署在localhost:
{
"name": "first-class",
"homepage": ".",
部署到github
也可以將pwa部署到github pages,部署到github pages的好處是github提供https,這時候,就要將homepage改為github page的網址:
{
"name": "first-class",
"homepage": "https://jitsungwu.github.io/mobile/",
部署時,可以注意到也會先進行build,只是不是利用localhost:5000,而是在github上執行。
執行
npm run deploy
事實上,執行deploy會自動執行build,所以,不需要先執行build。
現在,你終於可以利用手機,輸入網址,就可以看到我們的App,還可以把App新增到手機的主畫面!! 接下來,試試上上週的功能,上傳一張手機裡的照片。
firestore
firestore提供了離線讀取資料的功能,只要啟動了PWA並且使用onSnapshot,firestore就會自動啟動離線讀取資料。如果想知道現在的資料是從cache讀取或從server讀取,可以加上:
var source = querySnapshot.metadata.fromCache ? "local cache" : "server";
console.log("Data came from " + source);
完整程式區塊:
db.collection("product").orderBy("price", "desc").onSnapshot((querySnapshot)=>{
var source = querySnapshot.metadata.fromCache ? "local cache" : "server";
console.log("Data came from " + source);
querySnapshot.forEach((doc)=>{
const newProduct = {
id:doc.id,
desc:doc.data().desc,
price:doc.data().price
}
newProducts.push(newProduct);
console.log(doc.data().desc);
}
)
setProducts(newProducts);
setIsLoading(false);
});
** 還沒弄清楚為何get()無法使用 **
const querySnapshot = await db.collection("product").orderBy("price", "desc").get();
常見問題
在iOS上需要注意什麼?
參考資料
New Progressive Web App training now available (2021.5)
Progressive Web Apps in 100 Seconds // Build a PWA from Scratch (8:09)
What is a PWA
Tools of the Trade
Chrome Lighthouse
Workbox
PWA Asset Generator
Build a PWA from Scratch
Resources
7 Ways to PWA that you don't know (尚未完成)
Make it installable
Create an app-like user experience
Advanced topics
Progressive Web Apps Roadshow (8部影片) from Google
PWA Tutorial for Beginners (31部影片)
Progressive Web Apps (google)
What are Progressive Web Apps?
The three app pillars
Capable
The web is quite capable in its own right today. For example, you can build a hyper-local video chat app using WebRTC, geolocation, and push notifications.
Reliable
A reliable Progressive Web App feels fast and dependable regardless of the network.
Installable
Installed Progressive Web Apps run in a standalone window instead of a browser tab.
PWA (吳濟聰老師專題知識分享)