一、背景
taro 框架转的 h5,想在无网络状态下可以控制展示给用户的界面,使用客户端离线缓存可以达到目的,并且可以将静态资源进行缓存,从而减少白屏时间,加快页面相应速度。
二、service worker 简要介绍:
service worker 是一段脚本,在后台运行。作为一个独立的线程,不会对页面造成阻塞。本质上充当 Web 应用程序与浏览器之间的代理服务器。native app 可以做到离线使用、消息推送、后台自动更新,service worker 的出现是正是为了使得 web app 也可以具有类似的能力。在线上必须在 HTTPS 环境下才能工作,或者本地 localhost 域名也是可以的。
三、使用方法
第一步选择 npm 包,我用的是 sw-precache-webpack-plugin
这个包,基于 webpack 的插件,操作简单使用方便,详情请看文档
然后进行基于 webpack 的配置,下面例子是 taro 框架 h5 部分的配置内容
h5: {
publicPath: '/',
staticDirectory: 'static',
webpackChain(chain, webpack) {chain.plugin('sw')
.use(require('sw-precache-webpack-plugin'), [{
cacheId: 'name',
filename: 'service-worker.js',
filepath: path.resolve(__dirname, '../src/service-worker.js'),
// importScripts: [],
// 需缓存的文件配置, 需动态缓存的放到 runtimeCaching 中处理
staticFileGlobs: [],
mergeStaticsConfig: true,
minify: true,
verbose: true,
runTimeCaching: [
// 页面动态文件
{
urlPattern: /pages\/.*/,
handler: 'networkFirst'
},
{
urlPattern: /api\/.*/,
handler: 'networkFirst'
}
]
}]
);
},
module: {
postcss: {
autoprefixer: {enable: true}
}
}
}
ok, 现在已经配置完了,下一步只要在入口文件里注册 service-worker 就行啦,我是在 HTML 里加的,代码如下:
<script>
(function () {if ('serviceWorker' in navigator) {navigator.serviceWorker.register('./service-worker.js').then(function (registration) {
// 注册成功
console.log('ServiceWorker registration successful with scope:', registration.scope);
}).catch(function (err) {
// 注册失败
console.log('ServiceWorker registration failed:', err);
});
}
})();
</script>
大功告成,现在可以在本地调试了,本地如果启动了 webpack-dev-server,则需要:webpack 添加配置:
module.exports = {
devServer: {setup: function (app) {app.get('/service-worker.js', function (req, res) {res.set({ 'Content-Type': 'application/javascript; charset=utf-8'});
res.send(fs.readFileSync('build/service-worker.js'));
});
}
}
}
此时访问 localhost 就可以启用 service-worker 啦,如果配置了这些内容 service-worker 还没有注册成功的话,可能的原因如下:
- 你没有在 HTTPS 或 localhost 下运行你的项目。
- service worker 文件的地址没有写对— 需要相对于 origin , 而不是 app 的根目录。在我们的例子例,service worker 是在 https://mdn.github.io/sw-test…,app 的根目录是 https://mdn.github.io/sw-test/。应该写成 /sw-test/sw.js 而非 /sw.js.
- service worker 在不同的 origin 而不是你的 app 的,这是不被允许的。