歷時兩個月,PWA功能終於在web端穩定落地使用,網站 web.itiger.com。
從最新研究到落地上線,遇到不少坑;開發過程中也參考了不少資料,但總有那麼幾個是沒有答案,需要自己摸索結果的。所以,寫了這篇總結文章,也闡述一下我在開發過程中遇到的問題,以及解決辦法。
- 開發環境:vue+webpack,因為專案需要,vue版本v2.5.8,webpack版本v3.8.1
- Manifest.json配置
Manifest.json檔案配置的屬性是根據manifest的API完成的,其中稍作修改的有兩處。改動的原因:webpack打包後的static檔案路徑(https://static.itiger.com)和真正的訪問路徑(https://web.itiger.com)是在兩個不同的二級域名下,屬於跨域,所以對manifest的icon和引入路徑稍加配置。
(from: web.itiger.com )
1). icon的src屬性配置
因為將Manifest.json檔案放在static下,加上webpack的配置原因,icon圖片的路勁會稍有不同,為了避免錯誤和麻煩,直接將圖片轉成了base64編碼,也可以省去向伺服器請求icon圖片的時間,不佔用頻寬(如果圖片較小,頻寬的影響是可以忽略的)。
2). webpack打包後,manifest.json引入路徑
Manifest.json是在index.html內用link標籤引入的,如下所示:
<link rel="manifest" href="/manifest.json?<%=Date.now() %>">
(後面的引數:用打包時間做版本號識別)
但是manifest.json是放在/static資料夾下,經過webpack打包,正常來說也會在/dist/static資料夾下,但考慮上述提到的跨域問題,需要通過webpack(var CopyWebpackPlugin = require('copy-webpack-plugin'))引用依賴進行配置,將manifest.json檔案打包到/dist目錄下,便於訪問。
plugins: [
new CopyWebpackPlugin([
{
from: resolve('static/manifest.json'),
to: resolve('dist/manifest.json')
}
])
]
- Service worker配置
Service worker 的安裝註冊,是跟所有教程一樣的,不做贅述。可以在這裡進行查閱。
在本專案中,靜態快取借用了workbox-webpack-plugins,service worker.js內有手寫部分,所以沒有采用workbox 的GenerateSW()方法自動生成,而是用的InjectManifest(),對已有的sw.js檔案進行編輯。
因為workbox是存放在google的cdn上,考慮到客戶翻牆問題,就把workbox下載並傳到了tiger cdn上,所以,這邊涉及到workbox的import問題:
如果是從google的cdn引入,則webpack配置時importWorkboxFrom : cdn;
如果是從專案本地引入,則importWorkboxFrom : local;
如果是從其他地方(如tiger cdn)引入,則importWorkboxFrom : disabled,並且在service worker.js檔案內手動配置 importscript( ) 以及 workbox.core.setCacheNameDetails( ) 屬性。
一開始,是考慮將workbox安裝包放在專案內,但安裝包不小,所以放棄了這種方法改用放在tiger cdn上。但是剛開始的配置是importWorkboxFrom : cdn,所以導致service worker.js檔案中出現兩個workbox的引入路徑,造成引入失敗;最終將importWorkboxFrom設定成disabled就解決了。
- IndexedDB和Cache Storage快取清理
1). Cache storage實時更新資料時清除舊快取
Cachestorage 中會有三個快取,其中預快取內容存放在***-precache內
在進行靜態資源快取時,快取策略總會有選擇staleWhileRevalidate()的時候,此時的請求結果快取在***-runtime內,但會帶來一個快取問題。
用staleWhileRevalidate( )屬性所配置的靜態檔案,會從cache storage訪問,同時從network進行請求獲得最新的資料並更新cache的內容
(from: developers.google.com/web/fundame…)
Runtime-cache的內容永遠保持最新,但是之前的就快取也沒有被刪除,會導致本地快取量一直增加。
解決辦法:每次service worker被啟用時('activate',如重新整理頁面),新得到的請求結果在就快取被刪除後(waitUntil( ))再儲存
this.addEventListener('activate', function(event) {
var cacheWhitelist = [workbox.core.cacheNames.runtime];
event.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (cacheWhitelist.indexOf(key) >= 0) {
return caches.delete(key);
}
}))
})
)
})
2). 清除快取
當indexedDB和cache storage全部清空時,service worker.js 執行也不再有意義,所以要將service worker解除安裝,並重新改下載註冊。
if (window.navigator && navigator.serviceWorker) {
navigator.serviceWorker.getRegistrations()
.then(registrations => {
for (let registration of registrations) {
registration.unregister()
}
})
}
解除安裝之後再清空indexedDB和cache storage
indexedDB.deleteDatabase('indexedDB的名稱')
caches.keys().then((keyList) => {
if (!keyList.length) return
keyList.map((item) => {
caches.delete(item)
})
})
以上是該專案在落地PWA時遇到的一些坑和大家分享,有什麼問題的歡迎指正。