摘要:配合的項,能夠實現緩存外部資源的功能。允許接受來自的消息,默認值為。檢查新版本的的更新信息。這也是我在研究階段直接使用時所發現的問題。建議僅在生產模式內使用。
談起PWA,許多人可能還只停留在“了解”的層面,比較少在實踐中真正地嘗試過,更多的僅僅是對著網上的教程和例子大概玩過。然而,網絡上的例子多是簡單的demo,鮮有與真正的開發相結合,例如和webpack的工程化結合。這篇文章將會從一個webpack plugin出發,談一談如何使用這個名為offline-plugin的webpack插件輕松實現PWA。
由于PWA相關的文章太多,所以本文不再對“什么是PWA”,“PWA的生命周期”等基礎內容再次贅述。
offline-plugin相關鏈接:
offline-plugin
demo
一、自動生成service-worker.jsPWA的核心可謂是service-worker(以后簡稱SW),任何一個PWA都有且只有一個service-worker.js文件,用于為SW添加資源列表,進行注冊、激活等生命周期操作。但是在webpack構建的項目中,生成一個service-worker.js可能會面臨兩個較大的問題:
1、webpack生成的資源多會生成一串hash,sw的資源列表里面需要同步更新這些帶hash的資源;
2、每次更新代碼,都需要通過更新sw文件版本號來通知客戶端對所緩存的資源進行更新。(其實只要這一次的sw代碼和上一次的sw代碼不一樣即可觸發更新,但使用明確的版本號會更加合適)。
看到這你可能已經想到,萬能的webpack社區是否已經提供了相應的plugin來幫我們自動處理這些事情呢?答案是肯定的。除了官方推薦的sw-precache-webpack-plugin之外,還有我們今天的主角offline-plugin。
相比與sw-precache-webpack-plugin,個人認為offline-plugin具有如下優點:
1、更多的可選配置項,滿足更加細致的配置要求;
2、更為詳細的文檔和例子;
3、更新頻率相對更高,star數更多;
4、自動處理生命周期,用戶無需糾結生命周期的坑;
*5、支持AppCache;
6、自動生成manifest文件。
...
二、基本使用 安裝npm install offline-plugin [--save-dev]初始化
第一步,進入webpack.config:
// webpack.config.js example var OfflinePlugin = require("offline-plugin"); module.exports = { // ... plugins: [ // ... other plugins // it"s always better if OfflinePlugin is the last plugin added new OfflinePlugin() ] // ... }
第二步,把runtime添加到你的入口js文件當中:
require("offline-plugin/runtime").install();
ES6/Babel/TypeScript
import * as OfflinePluginRuntime from "offline-plugin/runtime"; OfflinePluginRuntime.install();
經過上面的步驟,offline-plugin已經集成到項目之中,通過webpack構建即可。
三、配置前面說過,offline-plugin支持細致的配置,以滿足不同的需求。下面將介紹幾個比較常用的配置項,方便大家進一步使用。
Caches: "all" | Object
告訴插件應該緩存什么東西,并以何種方式進行緩存 `all`: 意味著所有webpack構建出來的資源,以及在`externals`選項中的資源都會被緩存。 `Object`: 包含三個數組或正則的配置對象(`main`, `additional`, `optional`),它們都是可選的,且默認為空。 默認:`all`。
externals: Array
允許開發者指定一些外部資源(比如CDN引用,或者不是通過webpack生成的資源)。配合`Caches`的`additional`項,能夠實現緩存外部資源的功能。 默認:`null` 舉例:`["fonts/roboto.woff"]`
ServiceWorker: Object | null | false
該對象包含多個配置項,這里僅列舉最常用的。 `events`:布爾值。允許runtime接受來自sw的消息,默認值為false。 `navigateFallbackURL`:當一個URL請求從緩存或網絡都無法被獲取時,將會重定向到該選項所指向的URL。
AppCache: Object | null | false
`offline-plugin`默認支持`AppCache`,但是`AppCache`草案已經被web標準所廢棄,不建議使用。 但是由于仍然有部分瀏覽器支持,所以插件默認提供這個功能。四、runtime
上一節介紹了offline-plugin在webpack當中的配置,這一節將介紹runtime的一些用法。
若要使offline-plugin生效,用戶必須在入口js文件中通過runtime進行初始化操作:
// 通過AMD方式 require("offline-plugin/runtime").install(); // 或者通過ES6/Babel/TypeScript方式 import * as OfflinePluginRuntime from "offline-plugin/runtime"; OfflinePluginRuntime.install();
OfflinePluginRuntime對象提供了下列三個方法:
install(options: Object)
開啟ServiceWorker/AppCache的安裝流程。這個方法是安全的,并且必須在頁面初始化的時候就被調用。另外請勿把它放在任何的條件語句之內。(這句話不全對,在后面的降級方案里面會詳細介紹)
applyUpdate()
接受當前所安裝的sw的更新信息。
update()
檢查新版本的ServiceWorker/AppCache的更新信息。
runtime.install()方法接受一個配置對象參數,用于處理sw各個生命周期里面的事件:
onInstalled
當ServiceWorker/AppCache被install時執行,可用于展示“APP已經支持離線訪問”。
onUpdating
AppCache不支持該方法 當更新信息被獲取且瀏覽器正在進行資源更新時觸發。在這個時刻,一些資源正在被下載。
onUpdateReady
當`onUpdating`事件完成時觸發。這時,所有資源都已經下載完畢。 通過調用`runtime.applyUpdate()`方法來觸發更新。
onUpdateFailed
當`onUpdating`事件因為某些原因失敗時觸發。 這時沒有任何資源被下載,同時所有的資源更新進程都應該被取消或跳過。
onUpdated
當更新被接受時觸發。五、降級方案
當某些時候我們需要撤掉sw進行降級的時候,我們需要主動注銷sw。然而offline-plugin默認沒有提供注銷sw的unregister()方法,所以我們需要自己實現。
其實要主動注銷sw非常簡單,我們可以直接調用ServiceWorkerContainer.getRegistrations()方法來拿到registration實例,然后調用registration.unregister()方法即可,具體代碼如下:
if ("serviceWorker" in navigator) { navigator.serviceWorker.getRegistration().then((registration) => { registration && registration.unregister().then((boolean) => { boolean ? alert("注銷成功") : alert("注銷失敗") }); }) }
在調用該方法后,sw已經被注銷,刷新一下頁面就能看到資源是重新從網絡獲取的了。
在真實的生產環境中,我們可以通過調用接口,來決定是否使用降級方案:
fetch(URL).then((switch) => { if (switch) { OfflinePluginRuntime.install() } else { if ("serviceWorker" in navigator) { navigator.serviceWorker.getRegistration().then((registration) => { registration && registration.unregister().then((boolean) => { boolean ? alert("注銷成功") : alert("注銷失敗") }) }) } } })六、遇到的坑
在具體實踐中,遇到一個比較大的坑,就是sw.js文件的更新。
在service worker的設計中,瀏覽器每一次加載站點的URL,都會重新請求一遍sw.js。若發現這一次的sw.js內容和上一次的不一樣,就會判定為資源更新,重新觸發sw的生命周期。然而,sw.js也是一個普通的js資源文件,會默認使用服務器設置的expired時間,也就是它的max-age。在理解了service worker的設計后,我們不難發現,sw.js的max-age應該盡可能短,以便瀏覽器能夠及時更新資源列表。
這也是我在研究階段直接使用http-server時所發現的問題。后來在官方的例子中,我發現npm script里面是這么寫的:
"start": "http-server ./dist -p 7474 -c no-cache"
直接指定了所有資源都不使用緩存,這一點值得我們注意。
另外,webpack-dev-server里無法正常使用offline-plugin,因為它需要具體的文件去生成sw.js,但是通過webpack-dev-server構建的項目,其文件是存放在內存中的,所以無法和offline-plugin正常搭配使用。建議僅在生產模式內使用offline-plugin。
七、添加到主屏手機瀏覽器都提供了“添加到主屏”的功能,但普通的網站添加到主屏,僅僅是把網站的書簽放到桌面。如果要想把網站以PWA的形式添加到主屏,我們需要一個manifest.json文件:
{ "name": "offline-plugin", "icons": [ { "src": "/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" } ], "theme_color": "#181743", "background_color": "#181743", "start_url": "/", "display": "standalone" }
然后,把這個manifest.json和其他靜態資源一并打包到網站根目錄即可:
示例地址:
打開chrome開發者工具,進入到Application一列,選擇Manifest,就可以看到效果了:
截止到目前(2017年8月15日),我所使用的iOS10.3.2版本的iPhone7手機,已經支持PWA了,效果如下:
經過查閱大量的資料,到目前為止,iOS并不支持PWA,但是可以通過在html里面添加幾個標簽,實現web頁面和原生APP相似的體驗效果:
應用圖標: 啟動畫面: 應用名稱: 全屏效果: 設置狀態欄顏色:
使用safari打開
添加到主屏后打開
離線后從主屏打開
打開任務管理器
可以看到,PWA無論從表現還是功能,都像一個獨立的APP那樣存在。
八、尾聲原來一直以為蘋果對PWA支持不好,但通過這次實踐,可以知道其實PWA也取得了極大的推進,開發者們可以開心地搭建自己的PWA啦!
結論不能下太早。。。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91391.html
摘要:前端日報精選理解的專題之偏函數譯理解事件驅動機制游戲開發前端面試中的常見的算法問題發布中文前端頁面傳參尚妝產品技術刊讀基礎系列二之實現大轉盤抽獎掘金指南眾成翻譯編程插入排序眾成翻譯源碼講解函數技術風暴初體驗個人文 2017-08-16 前端日報 精選 理解 JavaScript 的 async/awaitJavaScript專題之偏函數[譯]理解 Node.js 事件驅動機制Pokem...
摘要:而且,在接下來頁面的異步請求中,還能進行緩存嘗試這里配置的文件清單在安裝激活階段不會進行緩存,只有在監聽到網絡請求的時候才進行緩存。 基本知識普及請參考https://www.jianshu.com/p/623...https://zhuanlan.zhihu.com/p/... 下面簡單介紹一下插件的使用以下是我在項目中使用的配置webpack.prod.conf.js中 { ...
摘要:本篇不包含所有坑,暫時只記錄自己踩到的部分坑一安裝安裝最新版本安裝新增依賴這個在中,本身和它的是在同一個包中,中將兩個分開管理。我記錄下自己更新這個的過程,以下前半部分可以直接跳過。以下記錄踩坑過程。 本篇不包含所有坑,暫時只記錄自己踩到的部分坑 一.安裝 安裝webpack4最新版本 npm install --save-dev webpack@4 安裝新增依賴 webpack-c...
閱讀 2556·2021-09-22 15:25
閱讀 2963·2021-09-14 18:03
閱讀 1212·2021-09-09 09:33
閱讀 1700·2021-09-07 09:59
閱讀 2930·2021-07-29 13:50
閱讀 1500·2019-08-30 15:44
閱讀 1715·2019-08-29 16:22
閱讀 1287·2019-08-29 12:49