PWA 入门: 写个很是简单的 PWA 页面

Progressive Web Apps 是 Google 提出的用前沿的 Web 技术为网页提供 App 般使用体验的一系列方案。css

这篇文章里咱们来完成一个很是简单的 PWA 页面。html

一个 PWA 应用首先是一个网页, 能够经过 Web 技术编写出一个网页应用. 随后添加上 App Manifest 和 Service Worker 来实现 PWA 的安装和离线等功能。下面的教程基于 Migrate your site to a Progressive Web App 和 Google 给出的 sample 示例。完整代码访问 minimal-pwa 查看。git

准备工做

建议安装 http-server 和 ngrok 以便调试和查看。github

准备一个 HTML 文件, 以及相应的 CSS 等:web

<head> <title>Minimal PWA</title> <meta name="viewport" content="width=device-width, user-scalable=no" /> <link rel="stylesheet" type="text/css" href="main.css"> </head> <body> <h3>Revision 1</h3> <div class="main-text">Minimal PWA, open Console for more~~~</div> </body> 

添加 manifest.json 文件

为了让 PWA 应用被添加到主屏幕, 使用 manifest.json 定义应用的名称, 图标等等信息。npm

{ "name": "Minimal app to try PWA", "short_name": "Minimal PWA", "display": "standalone", "start_url": "/", "theme_color": "#8888ff", "background_color": "#aaaaff", "icons": [ { "src": "e.png", "sizes": "256x256", "type": "image/png" } ] } 

而后在 HTML 文件当中引入配置:json

<link rel="manifest" href="manifest.json" /> 

添加 Service Worker

Service Worker 在网页已经关闭的状况下还能够运行, 用来实现页面的缓存和离线, 后台通知等等功能。sw.js 文件须要在 HTML 当中引入:浏览器

<script> if (navigator.serviceWorker != null) { navigator.serviceWorker.register('sw.js') .then(function(registration) { console.log('Registered events at scope: ', registration.scope); }); } </script> 

后面咱们会往 sw.js 文件当中添加逻辑代码。在 Service Worker 当中会用到一些全局变量:缓存

  • self: 表示 Service Worker 做用域, 也是全局变量
  • caches: 表示缓存
  • skipWaiting: 表示强制当前处在 waiting 状态的脚本进入 activate 状态
  • clients: 表示 Service Worker 接管的页面

处理静态缓存

首先定义须要缓存的路径, 以及须要缓存的静态文件的列表, 这个列表也能够经过 Webpack 插件生成。app

var cacheStorageKey = 'minimal-pwa-1' var cacheList = [ '/', "index.html", "main.css", "e.png" ] 

借助 Service Worker, 能够在注册完成安装 Service Worker 时, 抓取资源写入缓存:

self.addEventListener('install', e => {
  e.waitUntil(
    caches.open(cacheStorageKey)
    .then(cache => cache.addAll(cacheList))
    .then(() => self.skipWaiting())
  )
})

调用 self.skipWaiting() 方法是为了在页面更新的过程中, 新的 Service Worker 脚本能当即激活和生效。

处理动态缓存

网页抓取资源的过程当中, 在 Service Worker 能够捕获到 fetch 事件, 能够编写代码决定如何响应资源的请求:

self.addEventListener('fetch', function(e) { e.respondWith( caches.match(e.request).then(function(response) { if (response != null) { return response } return fetch(e.request.url) }) ) }) 

真实的项目当中, 能够根据资源的类型, 站点的特色, 能够专门设计复杂的策略。fetch 事件当中甚至能够手动生成 Response 返回给页面。

 

更新静态资源

缓存的资源随着版本的更新会过时, 因此会根据缓存的字符串名称(这里变量为 cacheStorageKey, 值用了 "minimal-pwa-1")清除旧缓存, 能够遍历全部的缓存名称逐一判断决决定是否清除(备注: 简化的写法, Promise.all 中 return undefined 可能出错, 见评论):

self.addEventListener('activate', function(e) { e.waitUntil( Promise.all( caches.keys().then(cacheNames => { return cacheNames.map(name => { if (name !== cacheStorageKey) { return caches.delete(name) } }) }) ).then(() => { return self.clients.claim() }) ) }) 

 

在新安装的 Service Worker 中经过调用 self.clients.claim() 取得页面的控制权, 这样以后打开页面都会使用版本更新的缓存。旧的 Service Worker 脚本再也不控制着页面以后会被中止。

查看 Demo

执行命令:

http-server -c-1 # 注意设置关闭缓存, 这里用参数 -c-1
# 用另外一个终端
ngrok http 8080

桌面浏览器能够直接经过  访问, 从 DevTools 的 Application 标签能够看到 Service Worker。

因为 Service Worker 限制了使用 HTTPS 地址或者 localhost 地址, 在 Android Chrome 打开须要借助 ngrok 生成的 HTTPS 地址, 这样才能把 demo 添加到首屏。添加到首屏以后, 即使在离线状态下, 页面也能够打开。

 

从 DevTools 能够看到, 普通页面刷新时, 列表当中的静态资源都是从 Service Worker 获取的:

 

更新页面

页面被缓存以后, 就须要适当处理缓存失效时页面的更新。在这个 Demo 当中, 被缓存的资源是没法发起请求判断是否被更新的, 只有 sw.js 会自动根据 HTTP 缓存的机制尝试去判断应用是否被更新。

因此当页面发生修改时, 要同时对 sw.js 文件进行一次修改。好比在 HTML 当中更新版本到 2:

 

<h3>Revision 2</h3> 

同时 sw.js 文件当中也要进行一次修改, 保证文件发生改变, 同时缓存的名称也变改变了:

var cacheStorageKey = 'minimal-pwa-2' 

而后从新打开一次页面, 这个时候渲染的页面依然是旧的, 不过能够从 DevTools 看到 sw.js 被安装和激活。以后关闭页面, 再次打开, 就能够见到网页上的显示版本变成了 2。

 

注意: Demo 当中若是直接启动 http-server 而不使用 -c-1 关闭缓存, sw.js 可能被缓存住, 致使更新方案失败。这种状况下存在 Caches API 和 HTML caching 两层缓存, 须要进行清理才能完成更新。

更多

你还能够实现一个 App Shell, 能够用 Service Worker 实现后台通知等功能。

参考你的首个 Progressive Web App 了解更加详细的编写 PWA 应用的方式。

 

来个饿了么的连接给你们体验下 https://h5.ele.me/msite/

相关文章
相关标签/搜索