什么是 PWA
PWA
全称 Progressive Web Apps
(渐进式 Web
应用程序),旨在使用现有的 Web
技术提供用户更优的使用体验。
基本要求
可靠(Reliable)
一方面是指PWA
的安全性,PWA
只能运行在HTTPS
上;另一方面是指在网络不稳定或者没网情况下,PWA
依然可以访问。快速响应(Fast)
快速响应用户的交互行为,并且具有平滑流畅的动画、加载速度、渲染速度和渲染性能等。粘性(Engaging)
通过添加到桌面以及离线消息推送,能带来用户的第二次访问,并且依靠良好的用户体验吸引用户再次访问。
官网链接:Progressive Web Apps
PWA 的核心技术
PWA
不是一项单独的技术,技术包括 Manifest
、Service Worker
、Push API
& Notification API
、App Shell
& App Skeleton
等等技术,接下来我们重点介绍几项技术以及相关问题的解决方法。
manifest
manifest
是支持站点在主屏上创建图标的技术方案,并且定制 PWA 的启动画面的图标和颜色等,如下图:
chrome > 桌面图标 > 启动样式 > 打开效果
manifest
内容
1 | { |
manifest
属性
name
— 网页显示给用户的完整名称;short_name
— 这是为了在没有足够空间显示Web
应用程序的全名时使用;description
— 关于网站的详细描述;start_url
— 网页的初始相对URL
比如/
)display
— 应用程序的首选显示模式;fullscreen
- 全屏显示;standalone
- 应用程序将看起来像一个独立的应用程序;minimal-ui
- 应用程序将看起来像一个独立的应用程序,但会有浏览器地址栏;browser
- 该应用程序在传统的浏览器标签或新窗口中打开.
orientation
— 应用程序的首选显示方向;any
natural
landscape
landscape-primary
landscape-secondary
portrait
portrait-primary
portrait-secondary
background_color
— 启动屏的背景颜色;theme_color
— 网站的主题颜色;icons
— 定义了src
、sizes
和type
的图片对象数组,各种环境中用作应用程序图标的图像对象数组.
MDN
提供了完整的manifest
属性列表: Web App Manifest properties
manifest 使用
manifest
功能虽然强大,但是技术上并不难,就是一个外链的json
文件,通过link
来引入:
1 | <!-- 在 html 页面中添加以下 link 标签 --> |
manifest 验证
在开发者工具中的 Application Tab 左边有 Manifest 选项,你可以验证你的 manifest JSON 文件,并提供了 “Add to homescreen” .
Service Worker
Service Worker
是 PWA
中最重要的概念之一,它是一个特殊的 Web Worker
,独立于浏览器的主线程运行,特殊在它可以拦截用户的网络请求,并且操作缓存,还支持 Push
和后台同步等功能。
注册服务
在 install Service Worker
之前,要在主进程 JavaScript
代码里面注册它,注册是为了告诉浏览器我们的 Service Worker
文件是哪个,然后在后台,Service Worker
就开始安装激活。
1 | if ("serviceWorker" in navigator) { |
注册时,还可以指定可选参数 scope,scope 是 Service Worker 可以以访问到的作用域,或者说是目录。
1 | navigator.serviceWorker.register("/sw.js", { |
注册成功后,您可以通过转至 chrome://inspect/#service-workers
并寻找您的网站来检查 Service Worker
是否已启用。
安装 Service Worker 服务
install
事件绑定在 Service Worker
文件中,当安装成功后,install
事件就会被触发。
一般我们会在 install
事件里面进行缓存的处理,用到之前提到的 Cahce API
,它是一个 Service Worker
上的全局对象,可以缓存网络相应的资源,并根据他们的请求生成 key
,这个 API
和浏览器标准的缓存工作原理相似,但是只是针对自己的 scope
域的,缓存会一直存在,知道手动清楚或者刷新。
1 | const cacheName = "bs-0-0-1"; // 缓存名称 |
更新 Service Worker 服务
当你的 Service Worker
需要更新时, 需要经过以下步骤
- 更新您的服务工作线程
JavaScript
文件。 用户导航至您的站点时,浏览器会尝试在后台重新下载定义Service Worker
的脚本文件。 如果Service Worker
文件与其当前所用文件存在字节差异,则将其视为新 Service Worker。 - 新
Service Worker
将会启动,且将会触发install
事件。 - 此时,旧
Service Worker
仍控制着当前页面,因此新Service Worker
将进入waiting
状态。 - 当网站上打开的页面关闭时,旧
Service Worker
将会被终止,新Service Worker
将会取得控制权。 - 新
Service Worker
取得控制权后,将会触发其activate
事件。
如果希望在有了新版本时,所有的页面都得到及时自动更新怎么办呢?可以在 install 事件中执行 self.skipWaiting() 方法跳过 waiting 状态,然后会直接进入 activate 阶段。接着在 activate 事件发生时,通过执行 self.clients.claim() 方法,更新所有客户端上的 Service Worker。
当 Service Worker
安装完成后并进入激活状态,会触发 activate
事件。通过监听 activate
事件你可以做一些预处理,如对旧版本的更新、对无用缓存的清理等。
1 | // 监听 activate 事件,激活后通过cache的key来判断是否更新、删除 cache 中的静态资源 |
处理动态请求缓存
在 Service Worker
的作用域中,当有网络请求时发生时,fetch
事件将被触发。它调用 respondWith()
方法来劫持网络请求缓存并返回:
1 | var apiCacheName = "api-0-1-1"; |
到这里,离线缓存动静态资源就完成了。
使用 Lighthouse 测试我们的应用
至此,我们完成了 PWA
的两大基本功能:Web App Manifest
和 Service Worker
的离线缓存。这两大功能可以很好地提升用户体验与应用性能。我们用 Chrome
中的 Lighthouse
来检测一下目前的应用:
可以看到,在 PWA
评分上,我们的这个 WebApp
已经非常不错了。
完整代码 -> 梦魇小栈 PWA 完整代码
1 | var cacheName = "bs-0-0-2"; |
由于现在博客仅需 Manifest
、Service Worker
后面的技术、Push API
& Notification API
、App Shell
& App Skeleton
等打算以后有时间在考虑场景加上~