PWA 入門: 寫個很是簡單的 PWA 頁面

Progressive Web Apps 是 Google 提出的用前沿的 Web 技術爲網頁提供 App 般使用體驗的一系列方案。css

這篇文章裏咱們來完成一個很是簡單的 PWA 頁面。html

一個 PWA 應用首先是一個網頁, 能夠經過 Web 技術編寫出一個網頁應用. 隨後添加上 App Manifest 和 Service Worker 來實現 PWA 的安裝和離線等功能。下面的教程基於 Migrate your site to a Progressive Web App 和 Google 給出的 sample 示例。完整代碼訪問 minimal-pwa 查看。git

準備工做

建議安裝 http-server 和 ngrok 以便調試和查看。github

準備一個 HTML 文件, 以及相應的 CSS 等:web

<head> <title>Minimal PWA</title> <meta name="viewport" content="width=device-width, user-scalable=no" /> <link rel="stylesheet" type="text/css" href="main.css"> </head> <body> <h3>Revision 1</h3> <div class="main-text">Minimal PWA, open Console for more~~~</div> </body> 

添加 manifest.json 文件

爲了讓 PWA 應用被添加到主屏幕, 使用 manifest.json 定義應用的名稱, 圖標等等信息。npm

{ "name": "Minimal app to try PWA", "short_name": "Minimal PWA", "display": "standalone", "start_url": "/", "theme_color": "#8888ff", "background_color": "#aaaaff", "icons": [ { "src": "e.png", "sizes": "256x256", "type": "image/png" } ] } 

而後在 HTML 文件當中引入配置:json

<link rel="manifest" href="manifest.json" /> 

添加 Service Worker

Service Worker 在網頁已經關閉的狀況下還能夠運行, 用來實現頁面的緩存和離線, 後臺通知等等功能。sw.js 文件須要在 HTML 當中引入:瀏覽器

<script> if (navigator.serviceWorker != null) { navigator.serviceWorker.register('sw.js') .then(function(registration) { console.log('Registered events at scope: ', registration.scope); }); } </script> 

後面咱們會往 sw.js 文件當中添加邏輯代碼。在 Service Worker 當中會用到一些全局變量:緩存

  • self: 表示 Service Worker 做用域, 也是全局變量
  • caches: 表示緩存
  • skipWaiting: 表示強制當前處在 waiting 狀態的腳本進入 activate 狀態
  • clients: 表示 Service Worker 接管的頁面

處理靜態緩存

首先定義須要緩存的路徑, 以及須要緩存的靜態文件的列表, 這個列表也能夠經過 Webpack 插件生成。app

var cacheStorageKey = 'minimal-pwa-1' var cacheList = [ '/', "index.html", "main.css", "e.png" ] 

藉助 Service Worker, 能夠在註冊完成安裝 Service Worker 時, 抓取資源寫入緩存:

self.addEventListener('install', e => {
  e.waitUntil(
    caches.open(cacheStorageKey)
    .then(cache => cache.addAll(cacheList))
    .then(() => self.skipWaiting())
  )
})

調用 self.skipWaiting() 方法是爲了在頁面更新的過程中, 新的 Service Worker 腳本能當即激活和生效。

處理動態緩存

網頁抓取資源的過程當中, 在 Service Worker 能夠捕獲到 fetch 事件, 能夠編寫代碼決定如何響應資源的請求:

self.addEventListener('fetch', function(e) { e.respondWith( caches.match(e.request).then(function(response) { if (response != null) { return response } return fetch(e.request.url) }) ) }) 

真實的項目當中, 能夠根據資源的類型, 站點的特色, 能夠專門設計複雜的策略。fetch 事件當中甚至能夠手動生成 Response 返回給頁面。

 

更新靜態資源

緩存的資源隨着版本的更新會過時, 因此會根據緩存的字符串名稱(這裏變量爲 cacheStorageKey, 值用了 "minimal-pwa-1")清除舊緩存, 能夠遍歷全部的緩存名稱逐一判斷決決定是否清除(備註: 簡化的寫法, Promise.all 中 return undefined 可能出錯, 見評論):

self.addEventListener('activate', function(e) { e.waitUntil( Promise.all( caches.keys().then(cacheNames => { return cacheNames.map(name => { if (name !== cacheStorageKey) { return caches.delete(name) } }) }) ).then(() => { return self.clients.claim() }) ) }) 

 

在新安裝的 Service Worker 中經過調用 self.clients.claim() 取得頁面的控制權, 這樣以後打開頁面都會使用版本更新的緩存。舊的 Service Worker 腳本再也不控制着頁面以後會被中止。

查看 Demo

執行命令:

http-server -c-1 # 注意設置關閉緩存, 這裏用參數 -c-1
# 用另外一個終端
ngrok http 8080

桌面瀏覽器能夠直接經過  訪問, 從 DevTools 的 Application 標籤能夠看到 Service Worker。

因爲 Service Worker 限制了使用 HTTPS 地址或者 localhost 地址, 在 Android Chrome 打開須要藉助 ngrok 生成的 HTTPS 地址, 這樣才能把 demo 添加到首屏。添加到首屏以後, 即使在離線狀態下, 頁面也能夠打開。

 

從 DevTools 能夠看到, 普通頁面刷新時, 列表當中的靜態資源都是從 Service Worker 獲取的:

 

更新頁面

頁面被緩存以後, 就須要適當處理緩存失效時頁面的更新。在這個 Demo 當中, 被緩存的資源是沒法發起請求判斷是否被更新的, 只有 sw.js 會自動根據 HTTP 緩存的機制嘗試去判斷應用是否被更新。

因此當頁面發生修改時, 要同時對 sw.js 文件進行一次修改。好比在 HTML 當中更新版本到 2:

 

<h3>Revision 2</h3> 

同時 sw.js 文件當中也要進行一次修改, 保證文件發生改變, 同時緩存的名稱也變改變了:

var cacheStorageKey = 'minimal-pwa-2' 

而後從新打開一次頁面, 這個時候渲染的頁面依然是舊的, 不過能夠從 DevTools 看到 sw.js 被安裝和激活。以後關閉頁面, 再次打開, 就能夠見到網頁上的顯示版本變成了 2。

 

注意: Demo 當中若是直接啓動 http-server 而不使用 -c-1 關閉緩存, sw.js 可能被緩存住, 致使更新方案失敗。這種狀況下存在 Caches API 和 HTML caching 兩層緩存, 須要進行清理才能完成更新。

更多

你還能夠實現一個 App Shell, 能夠用 Service Worker 實現後臺通知等功能。

參考你的首個 Progressive Web App 瞭解更加詳細的編寫 PWA 應用的方式。

 

來個餓了麼的連接給你們體驗下 https://h5.ele.me/msite/

相關文章
相關標籤/搜索