PWA应用与Service Worker

本文最后更新于:2022年8月19日 中午

体验我的PWA版小工具~

什么是PWA应用

PWA: Progressive Web Apps,渐进式 Web 应用

简单来说, 就是一种允许用户将web页面作为应用程序安装的技术。

一方面,Web 应用更加易于发现:相比于安装应用,访问一个网站显然更加容易和迅速。你还可以通过链接来分享 Web 应用。

另一方面,原生应用与操作系统可以更加完美的整合,也因此为用户提供了无缝的用户体验。你可以通过安装应用使得它在离线的状态下也可以运行;相较于使用浏览器访问,用户也更喜欢通过点击主页上的图标来访问它们喜爱的应用。[2]

当你打开一个网站时, 最能直观展示他是不是PWA的就是看chrome会不会弹出一个”安装”按钮

angular文档就是一个pwa应用

什么是Service Worker

Service Worker 是浏览器和网络之间的虚拟代理。 它们终于解决了前端开发人员多年来一直在努力解决的一些问题,其中最值得关注的是,解决了如何正确缓存网站资源并使其在离线时可用的问题。

Service Worker 运行在一个与页面 JavaScript 主线程独立的线程上,并且无权访问 DOM 结构。这引入了一种与传统 Web 编程不同的方式:它的 API 是非阻塞的,并且可以在不同的上下文之间发送和接收信息。您可分配给 Service Worker 一些任务,并通过基于 Promise 的方法在任务完成时收到结果。

它不仅仅提供离线功能,还可以做包括处理通知、在单独的线程上执行繁重的计算等事务。Service workers 非常强大,因为他们可以控制网络请求、修改网络请求、返回缓存的自定义响应,或者合成响应。[1]

简单来说, Service Worker就是一个位于浏览器和互联网间的代理, 可以拦截, 处理, 缓存HTTP请求, 同时可以实现通知推送离线缓存

下图展示了一个简洁的service worker的角色示意图[3]

service worker的工作模式

一个详细的angular实现service worker通知的教程

https://blog.angular-university.io/angular-push-notifications/

Angular创建一个pwa应用

之前一段时间我写了一些前端的小demo并作为一个工具合集放在一个网站里:

https://tools.roccoshi.top

下面展示一下以Angular为例, 创建一个pwa应用的过程, react和vue框架使用的更加广泛, 应该也有相应的配置

以下内容主要参考angular官方文档, 加上个人的一些实践的理解和踩坑, 内容可能会因angular版本不同而有所不一致, 可参考: https://angular.cn/guide/service-worker-getting-started

安装angular/pwa

注意pwa一定要安装对应angular-cli版本的

具体可以参考https://www.npmjs.com/package/@angular/pwa

选择对应tag的版本, 如我的angular-cli是v9, 则使用下面的方式安装:

1
npx ng add @angular/pwa@0.901.15 --project "tiny-tools"

这一步会进行如下操作:

  1. 把 @angular/service-worker 添加到你的项目中。
  2. 在 CLI 中启用 Service Worker 的构建支持。
  3. 在应用模块中导入并注册 Service Worker。
  4. 修改 index.html 文件:
    • 包含要添加到 manifest.webmanifest 文件中的链接。
    • theme-color 添加 meta 标签。
  5. 创建图标文件,以支持安装渐进式应用(PWA)。
  6. 创建一个名叫 ngsw-config.json 的 Service Worker 配置文件,它会用来指定缓存的行为以及其它设定。[4]

我们观察nsgw-config.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/manifest.webmanifest",
"/*.css",
"/*.js"
]
}
}, {
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**",
"/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
]
}
}
]
}

这是一个指定缓存的配置文件, 该文件表示浏览器将离线缓存这些内容:

  • index.html
  • favicon.ico
  • 构建结果(JS 和 CSS 包)
  • assets 下的一切
  • 图片和字体直接位于所配置的 outputPath (默认为 ./dist/<project-name>/) 或 resourcesOutputPath 下。关于这些配置的更多信息,请参阅 ng build

到这里, 我们就可以重新ng build构建我们的项目, 注意:

ng serve并不会使项目工作在service worker模式下, 需要使用一个独立的http服务器在本地测试, 可以使用npm的http-server包:

1
http-server -p 8080 -c-1 dist/<project-name>

这时就可以在本地愉快地测试你的pwa应用了!

发布

我的https://tools.roccoshi.top/基于github pages, 这里给出一个发布的参考

1
2
3
4
5
6
7
# 这一步是构建应用, 注意base-href表示你需要发布网站的url地址
call npx ng build --prod --base-href "https://tools.roccoshi.top/"
# 这一步是为了将github pages自定义域名所需的CNAME文件加入到构建文件夹中
call echo tools.roccoshi.top > ./dist/tiny-tools/browser/CNAME
# 使用gh-pages发布, 需要提前npm install gh-pages
call npx gh-pages -d dist/tiny-tools/browser
pause

这里注意构建的产物不一定在dist/<project-name>/browser中, 这里是因为我设置了app-shell, 如果没有使用app-shell构建的产物应该就在dist/<project-name>

等github action构建完毕后打开页面:

就可以发现支持安装啦~

安装后的界面大概就长这样:

可以直接在windows菜单栏打开, 也可以拖到桌面之类的, 本质还是一个浏览器页面

如果你使用edge, 还可以在设置 => 应用

管理安装的PWA应用程序

解决刷新后404的问题

上面的发布我遇到了一个棘手的问题, 导致卡了很久, 这个问题来源于浏览器的两种路由模式:

  • hash(#)模式
  • history模式

hash模式的url大概长这样: https://abc.com/#/page

history模式的url大概长这样: https://abc.com/page

angular默认使用的路由模式就是history模式, 但是在pwa中会导致一个问题:

如果你直接基于路由访问一个页面, 而不是先访问主页, 会404错误:

比如你直接访问https://tools.roccoshi.top/code-comparison而不是由https://tools.roccoshi.top导航而来, 会直接报404

我找到的相关的issue:

目前我也不清楚原因具体出在哪, 我觉得并不是路由模式的问题, 应该是哪个配置项出错了.

不清楚原因, 而且也极难搜到完全正确的解决方式, 我怀疑是路由或PWA配置的某个地方出现了问题, 最终尝试换成hash模式的路由, 也就是将:

1
RouterModule.forRoot(routes),

更换为

1
RouterModule.forRoot(routes, {useHash: true}),

就可以正常直接访问子路由页面了

关于PWA应用的看法

这篇文章: 小程序鼻祖 —— 在国内逐渐消亡的 PWA 可以带给我们哪些启示? - SegmentFault 思否我觉得说的很好

由于中国的特殊性,PWA 的前景在一定程度上比较悲观:

  • 国内较重视 iOS,而 iOS 目前还不支持 PWA。
  • 国内的 Android 实为「安卓」,不自带 Chrome 是一,可能还会有其他兼容问题。
  • 国内厂商可能并不会像三星那样对推动自家浏览器支持 PWA 那么感兴趣。
  • 依赖 GCM 推送的通知不可用,Web Push Protocol 还没有国内的推送服务实现。
  • 国内 webview 环境较为复杂(比如微信),黑科技比较多。

由于浏览器的限制, 兼容性的问题, 以及国内移动网络的高度普及化, PWA在我国市场注定是不会再火起来了, 所以这篇文章纯属了解和娱乐, 具体的技术栈我也不打算深入研究了~

参考


PWA应用与Service Worker
https://blog.roccoshi.top/posts/20684/
作者
RoccoShi
发布于
2022年8月18日
许可协议