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 所缓存,区别详细以下