在本文中,您将学习如何将 Workbox 和 IndexedDB 一起使用,创建离线优先、数据驱动的渐进式Web应用程序(PWA)。即使关闭了Web应用程序,也可以使用后台同步功能将应用程序与服务器同步。
你将会学习到
- 如何使用 Workbox 缓存应用程序
- 如何使用 IndexedDB 存储数据
- 如何在用户脱机时从 IndexedDB 中检索和显示数据
- 脱机时如何保存数据
- 如何在脱机时使用后台同步更新应用程序
你应该了解的
- HTML, CSS, 和 Javascript
- ES2015 Promises
- 如何使用命令行
- 熟悉一下 Workbox
- 熟悉一下 Gulp
- 熟悉一下 IndexedDB
你需要的
- 拥有 terminal/shell 访问权限的电脑
- 能上网
- Chrome
- 编辑器
- Nodejs 和 npm
设置
如果你没有安装 Nodejs 需要安装一下
之后通过下面的方式 clone 模板仓库
git clone https://github.com/googlecodelabs/workbox-indexeddb.git
或者直接下载 压缩包
安装依赖并启动服务
到下载好的 git 仓库目录中,转到 project
文件夹
cd workbox-indexeddb/project/
然后安装依赖并启动服务
npm install
npm start
说明
这个步骤中会根据 package.json
定义的依赖并安装,打开 package.json
文件检查,会看到很多依赖,有很多是开发环境需要的(你可以忽略),主要的依赖是:
- workbox-sw Workbox
- workbox-background-sync 是 Workbox 用来后台同步的,稍后会提到
- gulp 和 workbox-build 是构建工具
npm start
会构建并输出到 build
文件夹,启动 dev server,并且会开启一个 gulp watch
任务。 gulp watch
会监听文件的修改自动构建。 concurrently
可以同时跑 gulp
和 dev server
打开程序
打开 Chrome 并且跳转到 localhost:8081
你会看到一个事件列表的控制台,在弹出的权限确认菜单中点击允许
我们使用通知系统来告知用户程序的后台同步已经更新,试着测试一下页面底部的添加功能
说明
这个小项目的目标是离线保存用户的事件日历。你可以查看一下 app/js/main.js
文件的 loadContentNetworkFirst
方法看一下当前是怎么工作的,首先会请求 server,成功则更新页面,失败会在控制台打印一个信息,目前脱机是无法使用的,接下来我们添加一些方法使它脱机可用。
缓存我们的应用程序
编写 service worker
要想脱机工作,就需要 server worker,现在写一个。
把下面的代码添加到 app/src/sw.js
importScripts('workbox-sw.dev.v2.0.0.js');
importScripts('workbox-background-sync.dev.v2.0.0.js');
const workboxSW = new WorkboxSW();
workboxSW.precache([]);
保存。
说明
在开头我们引入了 workbox-sw
和 workbox-background-sync
-
workbox-sw
包含了预缓存和向 service worker 添加路由的方法
-
workbox-background-sync
是在 service worker 中后台同步的库,稍后会提到
precache
方法接收一个文件列表的数组,注意现在先用一个空数组占位,下一步我们会用 workbox-build
去计算出这个数组的结果。
构建 service worker
推荐使用 Workbox 的构建模块,比如 workbox-build
把下面的代码添加进 project/gulpfile.js
gulp.task('build-sw', () => {
return wbBuild.injectManifest({
swSrc: 'app/src/sw.js',
swDest: 'build/service-worker.js',
globDirectory: 'build',
staticFileGlobs: [
'style/main.css',
'index.html',
'js/idb-promised.js',
'js/main.js',
'images/**/*.*',
'manifest.json'
],
templatedUrls: {
'/': ['index.html']
}
}).catch((err) => {
console.log('[ERROR] This happened: ' + err);
});
});
现在取消一些注释:
gulpfile.js:
// uncomment the line below:
const wbBuild = require('workbox-build');
// ...
gulp.task('default', ['clean'], cb => {
runSequence(
'copy',
// uncomment the line below:
'build-sw',
cb
);
});
保存修改,因为修改了 gulp,所以我们得重新跑一下, Ctrl + C
退出当前的进程,重新运行 npm start
,会看到 service worker 的文件被生成在了 build/service-worker.js
取消 app/index.html
中 service worker 的注册代码
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js')
.then(function(registration){
console.log('Service Worker registration successful with scope: ',
registration.scope);
})
.catch(function(err){
console.log('Service Worker registration failed: ', err);
});
}
保存修改,刷新浏览器 service worker 就会被安装。 Ctrl + C
关闭 dev server,再返回到浏览器中刷新页面,已经可以脱机运行了!
说明
在这一步中, workbox-build
和 build-sw
任务被合并到我们的 gulp 文件中,我们的构建过程是使用 workbox-build
库来从 swSrc(app/src/sw.js)
中生成 service work 到 swDest(build/service-worker.js)
,来自 globDirectory(build)
的 staticFileGlobs
文件被注入到 build/service-worker.js
以供 precache
调用,还有每个文件的修订哈希。templatedUrls 选项告诉 Workbox 我们的站点以 index.html 的内容响应请求,因此我们不必管理两个单独的预缓存条目。
安装生成好的 service worker 预缓存应用程序的资源文件,Workbox 会自动去:
- 为缓存资源设置缓存优先策略,允许应用程序离线加载
- service work 更新时,使用修订哈希来更新缓存的文件
创建 IndexedDB 数据库
目前为止还不能离线加载数据,我们接下来创建一个 IndexDB 数据库来保存程序的数据,我们命名为 dashboardr
添加下面代码到 app/js/main.js
function createIndexedDB(){
if (!('indexedDB' in window)) {return null;}
return idb.open('dashboardr', 1, function(upgradeDb){
if (!upgradeDb.objectStoreNames.contains('events')) {
const eventsOS = upgradeDb.createObjectStore('events', {keyPath: 'id'});
}
})
}
取消 createIndexedDB
调用的注释:
const dbPromise = createIndexedDB();
保存文件,重启 server:
npm start
回到浏览器刷新页面,激活 skipWaiting 并再次刷新页面,在 Chrome 中,你可以在开发者 工具 中的 Application
面板中选择 Service Workers
点击 skipWaiting
,之后使用 开发者工具 检查数据库是否存在。在 Chrome 中你可以在 Application
面板中点击 IndexedDB
选择 dashboardr
查看 events
对象是否存在。