workbox 是 GoogleChrome 团队推出的一套 Web App 静态资源和请求结果的本地存储的解决方案,该解决方案包含一些 Js 库和构建工具,在 Chrome Submit 2017 上首次隆重面世。而在 workbox 背后则是 Service Worker 和 Cache API 等技术和标准在驱动。在 Workebox 之前,GoogleChrome 团队较早时间推出过 sw-precache 和 sw-toolbox 库,但是在 GoogleChrome 工程师们看来,workbox 才是真正能方便统一的处理离线能力的更完美的方案,所以停止了对 sw-precache 和 sw-toolbox 的维护。
从 sw-precache 和 sw-toolbox 的相关 issue 来看,众多开发者对它们也是颇有怨言。但是 workbox 发布了 2.x 版本后其实反响一般,总的来说我认为还是 api 太混乱了,虽然功能很强大但是设计条理不清晰,其学习成本导致很难推广开,但是从目前 workbox3 alpha 版本的文档和 API 来看,我个人认为 workbox3 终于成为了能够很方便简单的解决 Service Worker 绝大多数问题的神器,所以写这篇文章来全面介绍一下。
注意,当前 workbox 3 还是 alpha 发布阶段,API 和接口还有可能调整,文中所提到的一些工具可能 Google 方面还没有完全 ready, 本文为正式发布前的尝鲜版,后续正式发布后本会随版更新。
workbox 现在已经发布到了 3.0 alpha 版本,我们可以先了解一下 workbox:
bingo! 如果你被这些特性吸引住了,可以往下看看,我们在这里讲的是 workbox 3.0 的内容,当然 workbox 在解决的核心问题方面和之前的版本没有太大的出入,只是 API 进行了一些调整,并且在构建相关方面考虑的更加完善,workbox 进入 3.0 以后,API 看起来清晰多了,接下来一起看看 workbox 3 具体内容吧。
想要使用 workbox,首先需要在你的项目中创建一个 Service Worker 文件 sw.js 并且在你的站点上注册:
有了 sw.js 之后就可以使用 workbox 了,你只需要在 sw.js 中导入 workbox 就可以使用了:
// workbox 2.x 是将 workbox 核心内容放在 workbox-sw node_modules 包里维护的
// workbox 3.x 开始是将 workbox 核心 lib 放在 CDN 维护
// 当然也可以挪到自己的 CDN 维护
importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0-alpha.3/workbox-sw.js');
if (workbox) {
console.log(`Yay! workbox is loaded`);
}
else {
console.log(`Boo! workbox didn't load`);
}
当在 sw.js 能够拿到 workbox 全局变量,表明 workbox 可以使用了,workbox 能干什么呢?
如果你有一些静态资源是需要永远的离线缓存,除非重新上线才更新缓存的话,那 precache 预缓存应该是你所期待的,如果了解 Service Worker 的生命周期的话,precache 的工作是在 Service Worker install 时候通过 Cache API 完成的,具体可以了解 Service Work 生命周期。
workbox 提供了一种非常方便的 API 帮助我们解决 precache 的问题,和之前 Google 的 precache 方案 sw-precache 的工作类似。workbox 通过使用 precaching.precacheAndRoute 接口完成 precache 操作:
以上这段代码会在 Service Worker 安装成功的时候下载 /styles/index.0c9a31.css, /scripts/main.0d5770.js, /index.html 文件,并且会以构造路由的方式将这些文件都存储到 Cache Storage 中。这个传入的数组其实就是预缓存内容列表,有两种形式,一种是直接写文件名的字符串(带 Hash 的),一种是如下所示带有 url 和 revesion 值的对象:
{
url: '将要预缓存的文件 URL,
revision: '文件内容的 Hash 值'
}
这里需要注意的是这个 revision 的值,当预缓存的文件就任何变动的时候就会被更新,如果 revision 没有更新,那当你更新 Service Worker 的时候,被缓存的文件也不会被更新。
我们接下来介绍一些帮助我们生成预缓存内容列表的 precaching.precacheAndRoute API 的配置选项。
通常当用户访问 / 时,对应的访问的页面 HTML 文件是 /index.html,默认情况下,precache 路由机制会在任何 URL 的结尾的 / 后加上 index.html,这就以为着你预缓存的任何 index.html 都可以通过 /index.html 或者 / 访问到。
当然,你也可以通过 directoryIndex 参数禁用掉这个默认行为:
例如,如果我么想要让 key1 参数不是 /example.html?key1=1&key2=2 的一部分,你只需要设置 ignoreURLParametersMatching 参数把它排除掉:
这样 /example.html?key1=1&key2=2 这个路由对应的内容就可以被预缓存了。
靠手动维护 precache.precacheAndRoute API 中的预缓存内容列表是不可能的,revision 我们无法手动维护,所以我们肯定是要借助一些工具来干这个事情,好在 workbox 提供了多种方式让我们选择:
在使用以上三种方式生成预缓存内容列表之前,我们先预设一下应用场景:假设你的项目在目录 /app 下,必须保证在你的项目根目录下有一个 app/sw.js 包含以下内容:
这样才能保证能将生成的预缓存内容列表内容注入到 Service Worker 文件中。
workbox 提供了一套命令行,专门来帮助我们注入预缓存内容列表,可以帮助我们生成注入预缓存内容列表所需要的 workbox-cli-config.js 配置文件,然后通过命令行使用配置文件就可以生成一个预缓存列表的代码并注入到之前自定义的 app/sw.js 文件中,最终编译成线上所需要的 Service Worker 文件:dist/sw.js。
安装命令行:
所以我们先要有一个 workbox-cli-config.js 文件,然后根据这个文件结合 /app/sw.js 源文件来生成一个含有预缓存列表的 dist/sw.js 文件。接下来我们可以看下具体这一系列流程需要怎么操作。
首先执行 workbox generate:sw 命令生成一个配置文件 workbox-cli-config.js,这个命令执行之后将会弹出一些问题让你选择,如下所示:
回答完这些问题之后你就可以在你的项目里导出一个新的 workbox-cli-config.js 配置文件了大概长以下这个样子:
拿到了 workbox-cli-config.js 配置文件之后可以执行 workbox inject:manifest workbox-cli-config.js 命令生成编译后的 dist/sw.js 文件了,这一步干的事情就是把预缓存内容列表注入到 app/sw.js 中,一般只有在上线前才用命令行注入预缓存内容列表,通常我们都不会手动去执行这些命令的,比较合理的做法是实现生成好 workbox-cli-config.js 文件,然后在构建脚本中配置上自动执行 workbox inject:manifest 命令。
workbox inject:manifest 命令的做法就是去匹配 /app/sw.js 中的 workbox.precaching.precacheAndRoute([]) 方法的正则,然后通过 replace 内容注入的,可以参考下面的 workbox-build 的介绍。
使用命令行总感觉太傻了,操作步骤也比较繁琐,为了使得预缓存工作更加简便灵活,workbox 也提供了一个 NPM 包 – workbox-build,你可以在任何构建工具中都使用。
可以在你的工程根目录中执行以下命令安装 workbox-build 包:
然后直接可以在你想要处理 Service Worker 预缓存的地方引入 workbox-build 库,并且调用其 injectManifest 方法:
在构建文件中执行这段代码就会读取 app/sw.js 文件然后生成一个 dist/sw.js 文件含有注入的预缓存内容列表。
关于如何使用 injectManifest 方法可以查看 workbox-build 的 injectManifest 方法 全部参
有了 workbox-build 可想而知就能搞出很多实用的预缓存插件方案,比如 Webpack、Gulp 等插件,workbox 官方也提供了一个插件 workbox-webpack-plugin,只需要通过以下方式,就可以将插件安装到你的 webpack 项目中:
npm install --save-dev workbox-webpack-plugin
然后就只需要将插件添加到 Webpack 配置中就可以正常使用了,插件参数和 workbox-build 的 injectManifest 方法保持一致:
这里有个地方和之前提到的替换预留的 app/sw.js 不一样:使用 workbox 提供的 Webpack 插件必须在 app/sw.js 中包含以下代码才能完成预缓存内容列表注入工作
当插件跑起来之后,会在 /dist/sw.js 中增加一段 importScripts() 代码用来引入一个模块,这个模块的内容就是 self.__precacheManifest,也就是预缓存内容列表的内容,具体的效果可以在项目中使用 workbox-webpack-plugin 尝试一下,看看 build 后的 dist/sw.js 结果就会比较清楚了。
路由请求缓存是通过文件路由匹配的模式分别对制定的路由文件做不同策略缓存的方式,这部分工作可以在 app/sw.js 中直接使用 workbox 提供的 workbox.routing.registerRoute API 完成,这个 API 可以理解为干了两件事情,一、通过请求路由配置匹配到指定待缓存文件或请求内容,二、通过第二个参数的处理回调函数决定用何种策略来缓存匹配上的文件。有 三种 方法可以通过 workbox-route 来匹配一个请求 URL
上面讲到了匹配请求路由的三种方式,接下来可以讲讲如何处理匹配上的请求所返回的内容,也就是上面三种路由匹配方式的 handler,通常有两种做法:
下面介绍一下 workbox 默认提供的几种缓存策略 API,这些 API 可以被当成 handler 使用。
Stale While Revalidate
这种策略的意思是当请求的路由有对应的 Cache 缓存结果就直接返回,在返回 Cache 缓存结果的同时会在后台发起网络请求拿到请求结果并更新 Cache 缓存,如果本来就没有 Cache 缓存的话,直接就发起网络请求并返回结果,这对用户来说是一种非常安全的策略,能保证用户最快速的拿到请求的结果,但是也有一定的缺点,就是还是会有网络请求占用了用户的网络带宽。可以像如下的方式使用 State While Revalidate 策略:
Network First
这种策略就是当请求路由是被匹配的,就采用网络优先的策略,也就是优先尝试拿到网络请求的返回结果,如果拿到网络请求的结果,就将结果返回给客户端并且写入 Cache 缓存,如果网络请求失败,那最后被缓存的 Cache 缓存结果就会被返回到客户端,这种策略一般适用于返回结果不太固定或对实时性有要求的请求,为网络请求失败进行兜底。可以像如下方式使用 Network First 策略:
workbox.routing.registerRoute(
match, // 匹配的路由
workbox.strategies.networkFirst()
);
Cache First
这个策略的意思就是当匹配到请求之后直接从 Cache 缓存中取得结果,如果 Cache 缓存中没有结果,那就会发起网络请求,拿到网络请求结果并将结果更新至 Cache 缓存,并将结果返回给客户端。这种策略比较适合结果不怎么变动且对实时性要求不高的请求。可以像如下方式使用 Cache First 策略:
Network Only
比较直接的策略,直接强制使用正常的网络请求,并将结果返回给客户端,这种策略比较适合对实时性要求非常高的请求。可以像如下方式使用 Network Only 策略:
Cache Only
这个策略也比较直接,直接使用 Cache 缓存的结果,并将结果返回给客户端,这种策略比较适合一上线就不会变的静态资源请求。可以像如下方式使用 Cache Only 策略:
无论使用何种策略,你都可以通过自定义一个缓存来使用或添加插件(后面我们会介绍 workbox 插件)来定制路由的行为(以何种方式返回结果)。
当然,这些配置通常需要在缓存请求时更安全,也就是说,需要限制缓存的时间或者确保设备上用的数据是被限制的。
如果以上的那些策略都不太能满足你的请求的缓存需求,那就得想想办法自己定制一个合适的策略,甚至是不同情况下返回不同的请求结果,workbox 也考虑到了这种场景(这也是为什么我会极力推荐 workbox 的原因),当然,最简单的方法是直接在 Service Worker 文件里通过最原始的 fetch事件控制缓存策略。也可以使用 workbox 提供的另一种方式:传入一个带有对象参数的回调函数,对象中包含匹配的 url 以及请求的 fetchEvent 参数,回调函数返回的就是一个 response 对象,具体用法如下所示:
如果有些请求的域和当前 Web 站点不一致,那可以被认为是第三方资源或请求,针对第三方请求的缓存,因为 Workbox 无法获取第三方路由请求的状态,当请求失败的情况下 workbox 也只能选择缓存错误的结果,所以 workbox 3 原则上默认不会缓存第三方请求的返回结果。也就是说,默认情况下如下的缓存策略是不会生效的:
workbox.routing.registerRoute(
'https://notzoumiaojiang.com/example-script.min.js',
workbox.strategies.cacheFirst(),
);
当然,并不是所有的策略在第三方请求上都不能使用,workbox 3 可以允许 networkFirst 和 stalteWhileRevalidate 缓存策略生效,因为这些策略会有规律的更新缓存的返回内容,毕竟每次请求后都会更新缓存内容,要比直接缓存安全的多。
如果你强制使用 workbox 3 不推荐的缓存策略去缓存第三方请求,那 workbox 在 DevTools 里的 console 中会报警报哦。
如果你还是执意要缓存第三方请求的结果的话,workbox 3 也考虑到了确实会有这种难以扼杀的需求,提供了一个非常人性化的方式满足需求:利用 workbox.cacheableResponse.Plugin 来指定只缓存请求成功的结果,这样就打消掉我们之前对于不安全结果被缓存的顾虑了。鹅妹子英!(后面我们会介绍插件机制)
workbox.routing.registerRoute(
'https://notzoumiaojiang.com/example-script.min.js',
workbox.strategies.cacheFirst({
plugins: [
// 这个插件是让匹配的请求的符合开发者指定的条件的返回结果可以被缓存
new workbox.cacheableResponse.Plugin({
statuses: [0, 200]
})
]
}),
);
workbox 3 提供了一些配置项,都封装在 workbox.core API 中,可以稍微了解一下。
配置缓存名称
通过 DevTools -> Applications -> Caches 可以发现,workbox 对于缓存命名有一些规则的:
每个命名都有个前缀和后缀,中间才是真正的命名 ID,主要是为了更大限度的防止重名的情况发生,可以通过以下这种方式分别对 precache 和 runtime 形式的缓存进行自定义命名:
通过以上设置后,precache 类型的缓存名称为 my-app-custom-precache-name-<ID>-v1,runtime 类型的缓存名称为 my-app-custom-runtime-name-<ID>-v1。workbox 推荐尽量为你的每个项目设置不同的 prefix,这样你在本地 locahost 调试 Service Worker 的时候可以避免冲突。而 suffix 可以用来控制缓存版本,让站点的 Service Worker 更新机制变得清晰维护。
workbox 为了让 Web App 的缓存管理的更加细粒度的清晰可维护,也提供了策略级别的缓存命名设置,可以通过策略 API 的 cacheName 参数进行设置:
这样,对应的图片相关的 cacheFirst 策略的缓存都会以 my-image-cache-<ID> 的形式命名,这里要注意的是:prefix 和 suffix 是不需要设置的
指定 development 环境
workbox 开发过程中是需要 debug 的,所以 workbox 3 也提供了 logger 机制帮助我们排查问题,但是在生产环境下,我们不希望也产生 logger 信息,所以 workbox 提供了「指定当前环境」 的设置:
配置日志 Level
workbox 3 提供 logger 机制帮助我们更好的调试 workbox,一共有四种 log level:debug,log,warn,error。
可以通过以下方式设置 log 的 level,这样就可以只看到某个 level 的 log 信息,让调试的过程中更加专注。具体的设置方式是通过 worbox.core API 中的 setLogLevel 方法来完成:
插件机制应该是 workbox 3 最大的改进了,在 2.x 中,现有的插件大部分功能都是直接以 API 的形式抛给开发者,让开发者一头雾水,现在 3.0 中每个内置插件自己封装了之前的 API,对开发者来说专门解决了一个个独立的问题。除此之外,workbox 3 还提供插件扩展机制以及事件钩子可以让开发者自己扩展插件。workbox 插件可以让你通过操作一个请求的生命周期中的返回内容和请求内容添加其他的一些行为。
workbox 插件通常都是在缓存策略中使用的,可以让开发者的缓存策略更加灵活,workbox 内置了一些插件:
workbox.backgroundSync.Plugin: 如果网络请求失败,就将请求添加到 background sync 队列中,并且在下一个 sync 事件触发之前重新发起请求。
workbox.broadcastUpdate.Plugin: 当 Cache 缓存更新的时候将会广播一个消息给所有客户端,类似于 sw-register-webpack-plugin 做的事情。
workbox.cacheableResponse.Plugin: 让匹配的请求的符合开发者指定的条件的返回结果可以被缓存,可以通过 status, headers 参数指定一些规则条件。
workbox.expiration.Plugin: 管理 Cache 的数量以及 Cache 的时间长短。
可以像如下方式来使用 workbox 插件,以 workbox.expiration.Plugin 为例:
当然,workbox 也知道这些插件肯定不能满足大家的自定义策略的要求,所以索性将整个请求生命周期中的关键事件以事件钩子回调函数的方式暴露出来,也就是说,我们可以使用这些事件钩子打造自己更加灵活的 workbox 插件。一个插件就是一个构造函数,而钩子就是以构造函数的方法的形式供开发者们自定义开发,下面介绍一下有哪些事件钩子:
cacheWillUpdate
cacheWillUpdate({request, response}),在请求返回结果替换 Cache 结果之前被调用,你可以在这个事件钩子中在更新缓存之前修改返回的结果,如果将结果直接设为 null 来避免当前请求的返回的结果被更新到缓存。
cacheDidUpdate
cacheDidUpdate({cacheName, request, oldResponse, newResponse}),当有新的缓存写入记录或者 Cache 缓存被更新时被调用,你可以调用这个方法在 Cache 缓存更新之后干点什么。
cachedResponseWillBeUsed
cachedResponseWillBeUsed({cacheName, request, matchOptions, cachedResponse}),在 Cache 缓存的结果在 fetch 事件中被触发响应返回之前调用,可以使用这个回调来允许或阻止正在使用的 Cache 响应返回。
requestWillFetch
requestWillFetch({request}),当任何 fetch 事件被触发的时候都会被调用,可以在这个毁掉中修改请求的 request 内容。
fetchDidFail
fetchDidFail({originalRequest, request}),当 fetch 事件触发失败的时候被调用,fetch 事件触发失败是网络根本无法请求,而不是请求返回为 非 200 的状态的时候,可以用这个钩子在检测到断网的时候干点什么。
如果你想写一个自己的 workbox 插件,只需要参照如下方式:
本文参考了 Google 官方文档,在文档的基础上做了一些自己的解读和总结,有兴趣的开发者可以阅读原始文档,文档中还列出了一些「最佳实践」以及 「debug」 的方式,可以帮助我们更好的使用 workbox。
来源:https://zoumiaojiang.com/article/amazing-workbox-3/
通过技术的角度,来探讨如何提高网页加载速度的方法和技巧,一个网站速度的访问快慢将直接影响到用户体验,对于我们开发来说是应该解决的。
XSS攻击的全称Cross Site Scripting(跨站脚本攻击),为了避免和样式表CSS混淆而简写为XSS。XSS恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。
通过js或css禁止蒙层底部页面跟随滚动:pc端推荐给body添加样式overflow: hidden;height: 100%;移动端利用移动端的touch事件,来阻止默认行为,若应用场景是全平台我们要阻止页面滚动,那么何不将其固定在视窗(即position: fixed),这样它就无法滚动了,当蒙层关闭时再释放。
渐进式 Web 应用是利用现代浏览器的特性,可以添加到主屏幕上,表现得像原生应用程序一样的 Web 应用程序。
Web前端技术由 html、css 和 javascript 三大部分构成,是一个庞大而复杂的技术体系,其复杂程度不低于任何一门后端语言。而我们在学习它的时候往往是先从某一个点切入,然后不断地接触和学习新的知识点,因此对于初学者很难理清楚整个体系的脉络结构。
Web开发是比较费神的,需要掌握很多很多的东西,特别是从事前端开发的朋友,需要通十行才行。今天,本文向初学者介绍一些Web开发中的基本概念和用到的技术,从A到Z总共26项,每项对应一个概念或者技术。
Web浏览器的主要功能是展示网页资源,即请求服务器并将结果展示在窗口中。地址栏输入URL到页面显示经历的过程、浏览器的主要组件、浏览器渲染...
增强现实(以下简称 AR)浪潮正滚滚而来,Web 浏览器作为人们最唾手可得的人机交互终端,正在大力发展 AR 技术。AR 可以简单的理解为一种实时将虚拟图像叠加在现实场景中的技术
用户是否操作了web页面,我们可以在一定时间内根据用户是否触发了某些事件进行判断。比如用户是否点击,是否按键,是否移动了鼠标等
如今web服务随处可见,成千上万的web程序被部署到公网上供用户访问,有些系统只针对指定用户开放,属于安全级别较高的web应用,他们需要有一种认证机制以保护系统资源的安全,本文将探讨五种常用的认证机制及优缺点。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!