使用 Workbox 创建 PWA 应用
關注?前端瓶子君,回復“交流”
加入我們一起學習,天天進步
來源:悖論?
https://juejin.cn/post/6895306314747281421
前言
最近公司項目迭代逐漸放緩,下班時間逐漸變早,所以本著漸進增加的理念,在下班后,將公司項目進行了一下PWA改造
為何要改造成PWA
用戶需求。我們的用戶有許多電腦小白,不想記網址,又不會使用瀏覽器的收藏功能。以前使用的同類軟件都有桌面版,有一種覺得桌面版比網頁版可靠,使用簡單的錯覺,曾多次在釘釘售后群里反映,如何將網頁保存至桌面,方便他下次直接在桌面打開
PWA是漸進式的,如果用戶的瀏覽器不支持ServiceWorker等構建PWA所需的API,并不會對其造成使用上的影響,并且通過埋點平臺獲知,我們用戶Chrome瀏覽器數量占到80%左右
離線緩存,可安裝,可攔截fetch等功能,對我個人有一定的吸引力,希望學習使用
開始改造
為了快速改造成PWA, 我這里選擇使用了谷歌推出的PWA工具庫workbox, 并且結合webpack創建serviceWorker文件
安裝依賴
npm?install?--save-dev?workbox-webpack-plugin npm?install?--save?workbox-core?workbox-routing?workbox-strategies?workbox-precaching?workbox-expiration?workbox-cacheable-responseworkbox-webpack-plugin里提供了兩種插件,GenerateSW以及InjectManifest。
GenerateSW
GenerateSW插件可以通過配置直接編譯生成對應的serviceWorker文件,不需要我們直接編寫serviceWorker文件。使用方式大致如下:
import?{?InjectManifest?}?from?'workbox-webpack-plugin';new?GenerateSW({skipWaiting:?true,clientsClaim:?true,mode:?'development',runtimeCaching:?[{urlPattern:?/^https?\:\/\/.+?\.alicdn.com\/.+$/,handler:?'StaleWhileRevalidate'},], });通過GenerateSW編譯生成serviceWorker文件雖然簡單,但不夠靈活,所以實際上我使用了另一個InjectManifestPlugin插件
InjectManifest
InjectManifest主要做了兩件事
將webpack編譯生成的資源文件清單,以變量self.__WB_MANIFEST的形式注入到我們提供的serviceWorker模板文件中
編譯我們提供的模板文件,生成目標serviceWorker文件
使用方式大致如下:
const?{?InjectManifest?}?=?require('workbox-webpack-plugin'); new?InjectManifest({swSrc:?path.resolve('src/sw.js'),swDest:?path.resolve(BUILD_DEST,?'sw.js'), }),編寫serviceWorker模板文件
預緩存靜態資源
預緩存會在serviceWork激活后,立即請求并緩存所有預緩存清單中的文件, 之后下載請求同一資源時,會使用緩存優先策略,優先使用已經預緩存的資源
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);路由請求緩存
這里有一個需要注意的點,alicdn靜態資源與我司網頁域名不是同域名,存在跨域,當請求靜態資源的時候,會返回不透明響應(opaque response); 當我們使用Cache-First策略緩存不透明響應時,workbox會提示我們不要使用這個策略來緩存不透明響應,因為不透明響應對JavaScript來說是一個黑盒,無法獲取到正確的status code, headers, body, 所以我們緩存中的資源是不可靠的;并且當我們緩存不透明響應時,緩存所占有的空間遠大于實際資源的大小,容易造成DOMException: Quota exceeded.?所以需要處理下不透明響應的緩存
不透明響應變成透明響應
既然不透明響應會造成問題,那只要把不透明響應變成透明響應,那就應該沒問題了。
經過查看,我發現alicdn的響應頭會返回access-control-allow-origin: *, 后端是支持cors跨域資源共享的。既然如此,只要當我們請求靜態資源的時候,讓請求走cors應該就可以了。于是,我嘗試在其中一個img標簽中,啟用cors
不透明響應成功變成透明響應。但如果給所有<img /><script /><link />標簽添加crossorigin, 這工作量也太大了。有沒有統一處理的方法呢?有??梢酝ㄟ^攔截fetch請求來統一處理, 在使用workbox的場景下,可以通過設置緩存策略類中fetchOptions來實現
registerRoute(/^https?\:\/\/.*?\.alicdn.com\/.+?\.(css|js|png|jpg|jpeg|svg|gif|webp)$/,new?CacheFirst({cacheName:?'alicdn-cache',plugins:?[new?CacheableResponsePlugin({statuses:?[200]}),new?ExpirationPlugin({maxEntries:?300,maxAgeSeconds:?7?*?24?*?60?*?60,}),],//?添加如下fetch?optionsfetchOptions:?{mode:?'cors',credentials:?'omit',},}), );創建manifest.json文件
通過manifest配置文件,可以指定pwa應用的圖標,初始頁面,背景色,主題色,顯示模式等內容
//?manifest.json {???"name":?"xxx","short_name":?"xxx","icons":?[{"src":?"/static/images/favicon@144x144.png","sizes":?"144x144","type":?"image/png"}],"start_url":?"/index.html","display":?"standalone","background_color":?"#000","theme_color":?"#000" }<link?rel="manifest"?href="/manifest.json">結語
最后,我們的PWA應用改造就完成了。PWA技術是一系列技術的集合,這里,我只用到了serviceWorker, manifest,push/notification等沒有涉及到,如果日后有這個必要,再增加相應功能
延伸擴展
什么是不透明響應(opaque response)
簡單的說,不透明響應就是當我們使用fetch,并且設置no-cors,來請求跨域資源時獲取到的響應
fetch('https://www.baidu.com/img/flexible/logo/pc/result@2.png',?{mode:?'no-cors' }).then(response?=>?{return?console.log(response) }).catch(error?=>?{return?console.log(error) });打印的結果為
Response?{body:?nullbodyUsed:?falseheaders:?{},ok:?falseredirected:?falsestatus:?0statusText:?""type:?"opaque"url:?"" }從Response中,我們可以發現不透明響應
status為0,而非200等http status code
statusText為空
headers也為空
body也為空
總之,我們(JavaScript)獲取不到這個Response中的內容
最后
歡迎關注「前端瓶子君」,回復「交流」加入前端交流群!
歡迎關注「前端瓶子君」,回復「算法」自動加入,從0到1構建完整的數據結構與算法體系!
另外,每周還有手寫源碼題,瓶子君也會解答喲!
》》面試官也在看的算法資料《《
“在看和轉發”就是最大的支持
總結
以上是生活随笔為你收集整理的使用 Workbox 创建 PWA 应用的全部內容,希望文章能夠幫你解決所遇到的問題。