workbox
是 google 出的關於 service worker 生成預緩存列表,緩存策略,Background API 的一個庫,綜合了自家之前 sw-toolbox
以及 sw-precache
的功能。javascript
workbox
介紹了幾種緩存策略,workbox-strategies。html
Service Worker Cookbook
也對這幾種緩存策略作了介紹,caching-strategies。前端
可是關於這些策略的原理以及如何使用,強烈推薦谷歌開發者文檔中的 離線指南。java
使用緩存,咱們都會關心瀏覽器會提供多達的存儲空間,如下代碼能夠查看你的應用已使用了多少存儲空間以及有多大的配額react
navigator.storage.estimate().then(info => console.log(info.quota, info.usage))
另外也能夠在 chrome 的 devtool 中進行查看,Application -> clear storage -> usagewebpack
若是項目採用 create-react-app
腳手架搭建,內置了 sw-precache-webpack-plugin
這個離線化插件,因而就對它作了一些適配。它是基於 google 的 sw-precache 的一個插件。git
若是大家項目沒有使用 create-react-app
,建議使用 workbox
的 webpack Plugin,workbox 也是 google 新出的關於 service-worker 的工具。github
若是大家的靜態資源不在 CDN 上,Create React APP 已幫你寫好了 webpack 的配置。web
若是靜態資源在 CDN 上,就要略微折騰一番了。chrome
/index.html
與 /sw.js
須要在同域下,引用 /sw.js
時須要注意去掉 PUBLIC_PATH (webpackConfig.output.publicPath)
的前綴。
另外 sw-precache-webpack-plugin
生成 preCache 列表時,也會對 /index.html
添加上 PUBLIC_PATH
的前綴,須要替換掉,配置以下。其中 paths.appBuild 爲 webpackConfig.output.path
{ ...config, mergeStaticsConfig: true, stripPrefixMulti: { [`${paths.appBuild}/index.html`]: '/index.html' } }
如下是對於爲什麼如此操做的源碼分析
關於 stripPrefixMulti
,能夠查看 sw-precache
的文檔,sw-precache#stripprefixmulti-object。主要是處理 precache 文件的前綴的,如如下 源碼
// https://github.com/GoogleChromeLabs/sw-precache/blob/5.2.1/lib/sw-precache.js#L170 var relativeUrl = fileAndSizeAndHash.file .replace( new RegExp('^(' + Object.keys(params.stripPrefixMulti) .map(escapeRegExp).join('|') + ')'), function(match) { return params.stripPrefixMulti[match]; }) .replace(path.sep, '/');
能夠看出來它用來替換特定前綴。
而 sw-precache-webpack-plugin
中已經對它作了一些處理,查看 源碼
// https://github.com/goldhand/sw-precache-webpack-plugin/blob/v0.11.5/src/index.js#L119 if (outputPath) { // strip the webpack config's output.path (replace for windows users) stripPrefixMulti[`${outputPath}${path.sep}`.replace(/\\/g, '/')] = publicPath; }
它把 precache 文件列表的前綴所有替換爲了 publicPath (即 webpackConfig.output.publicPath),可是 /index.html
不能在 cdn 的路徑上,因此須要特殊配置一下。
stripPrefixMulti: { [`${paths.appBuild}/index.html`]: '/index.html' }
根據正則的短路原則,恰好能夠把 index.html 給替換回來。
'hello, world'.replace(/(hello, world)|(hello)/, 'shanyue') // shanyue
對於靜態資源,採起了全部靜態資源添加hash,除部署後第一次外均不需再訪問服務器。
若是這裏採用 workbox 的術語的話,那麼靜態資源則是採用了 Cache-First
的策略,當緩存不可取時纔回退到網絡,而對於動態 API,則採用 Network-First
的策略,只有在離線狀態下才使用緩存。
固然,若是你只想使用 service worker 作緩存控制的話,API 緩存就能夠跳過了。
如下代碼是 sw-precache-webpack-plugin
的配置,動態緩存利用了 google 的 sw-toolbox
工具,它提供瞭如 workbox 同樣的緩存策略。
{ runtimeCaching: [{ urlPattern: /api/, handler: 'networkFirst' }] }
GraphQL 的 query 是使用 http 的 POST 請求進行發送的,而 service worker 不支持對 POST 請求進行緩存。
Replaying POST requests by w3c@ServiceWorker
其實一想很正常,POST 是非冪等的,連 http 也不對它進行緩存。
GraphQL 的 query 支持 GET 請求,修改成 GET 是可行的。另一種方案是使用 apollo-cache-persist 對訪問過的數據進行持久化。
關於前端項目在生產環境中部署的問題是一個比較工程化的問題,關於具體實現方案簡單來講是以下兩點
能夠參考如下兩篇文章
可是有了 Service Worker 以後有以下幾個好處
注意要對 /sw.js 設置 Cache-Control: no-cache
。
http 的緩存策略雖然是把靜態資源緩存在瀏覽器中,可是緩存行爲的控制倒是在服務端的 - 如 http response 中的 Cache-Control。而 service worker 對緩存資源的控制權徹底在瀏覽器手中,而且能夠經過編程精度控制靜態資源,動態請求的數據等。
可是這不表明 service worker 能夠徹底控制 http 進行緩存控制,由於 http 不只僅緩存在瀏覽器中,還有代理緩存中。
在 http 的 Cache-Control 中有兩個參數,private 和 public。private 表明不被 proxy 所緩存,區別詳細以下