干货 | 10分钟玩转PWA

渐进式Web应用的要点

渐进式Web应用是一种新的技术,所以使用的时候一定要小心。也就是说,渐进式Web应用可以让您的网站在几个小时内得到改善,并且在不支持渐进式Web应用的浏览器上也不会影响网站的显示。

但是我们需要考虑以下几点:

serviceworker的缓存功能

安装时,serviceworker将我们指定的静态资源进行缓存,你也许会问,如果是实时的动态内容怎么办,我们不可能预先将所有的文件资源提前指定好,让serviceworker缓存。这就要提到serviceworker的拦截HTTP请求响应的特性了。

serviceworker拦截http请求,首先去检查请求的资源在缓存中是否存在,如果存在,则直接从缓存中调用,而且即便是无网络情况下,serviceworker也能调用缓存中的资源。如果缓存中没有请求的资源,则通过网络去服务器上检索,而且在找到并响应时,serviceworker会将其存入缓存中,以备下次再请求时直接从缓存中调用。

463.com 1serviceworker缓存流程

serviceworker文件中fetch事件代码如下:

self.addEventListener(‘fetch’, function {

event.respondWith(

caches.match(event.request).then(function{

if{

return response;

}

var requestToCache = event.request.clone();

return fetch(requestToCache).then(

function{

if(!response || response.status !== 200){

return response;

}

var responseToCache = response.clone();

caches.open(CACHE_VERSION)

.then(function{

cache.put(requestToCache, responseToCache);

});

return response;

}

);

})

);

});

在网站前台通过浏览器开发者工具,我们可以看下从缓存中调用资源的效果:

463.com 2serviceworker缓存调用463.com 3缓存文件

我这里操作演示用的是谷歌浏览器,下面是各大浏览器对于serviceworker的支持情况:

463.com 4serviceworker浏览器支持情况

第三步:创建一个 Service Worker

Service Worker
是一个可编程的服务器代理,它可以拦截或者响应网络请求。Service Worker
是位于应用程序根目录的一个个的JavaScript文件。

您需要在页面对应的JavaScript文件中注册该ServiceWorker:

if (‘serviceWorker’ in navigator) { // register service worker
navigator.serviceWorker.register(‘/service-worker.js’); }

1
2
3
4
if (‘serviceWorker’ in navigator) {
  // register service worker
  navigator.serviceWorker.register(‘/service-worker.js’);
}

如果您不需要离线的相关功能,您可以只创建一个 /service-worker.js文件,这样用户就可以直接安装您的Web应用了!

Service
Worker这个概念可能比较难懂,它其实是一个工作在其他线程中的标准的Worker,它不可以访问页面上的DOM元素,没有页面上的API,但是可以拦截所有页面上的网络请求,包括页面导航,请求资源,Ajax请求。

上面就是使用全站HTTPS的主要原因了。假设您没有在您的网站中使用HTTPS,一个第三方的脚本就可以从其他的域名注入他自己的ServiceWorker,然后篡改所有的请求——这无疑是非常危险的。

Service Worker 会响应三个事件:install,activate和fetch。

Service Worker

Service
Worker是PWA的核心技术,它能够为web应用提供离线缓存功能,当然不仅如此,下面列举了一些Service
Worker的特性:

基于HTTPS
环境,这是构建PWA的硬性前提。(LAMP环境网站升级HTTPS解决方案)

是一个独立的 worker 线程,独立于当前网页进程,有自己独立的 worker
context

可拦截HTTP请求和响应,可缓存文件,缓存的文件可以在网络离线状态时取到

能向客户端推送消息

不能直接操作 DOM

异步实现,内部大都是通过 Promise 实现

缓存过大

你不能将您网站中的所有内容缓存下来。对于小一些的网站来说缓存所有内容并不是一个问题,但是如果一个网站包含了上千个页面呢?很明显不是所有人对网站中的所有内容都感兴趣。存储是有限制的,如果您将所有访问过的页面都缓存下来的话,缓存大小会增长额很快。

你可以这样制定你的缓存策略:

  • 只缓存重要的页面,比如主页,联系人页面和最近浏览文章的页面。
  • 不要缓存任何图片,视频和大文件
  • 定时清理旧的缓存
  • 提供一个“离线阅读”按钮,这样用户就可以选择需要缓存哪些内容了。

Service Worker生命周期

serviceworker的使用流程可以简单总结为注册–安装–激活。

注册其实就是告诉浏览器serviceworkerJS文件存放在什么位置,然后浏览器下载、解析、执行该文件,进而启动安装。这里我创建一个app.js文件,注册代码如下,将该文件在网站的head标签里引入。

if (‘serviceWorker’ in navigator) {

window.addEventListener(‘load’, function () {

navigator.serviceWorker.register

.then(function (registration) {

// 注册成功

console.log(‘ServiceWorker registration successful with scope: ‘,
registration.scope);

})

.catch(function {

// 注册失败:(

console.log(‘ServiceWorker registration failed: ‘, err);

});

});

}

当执行serviceworkerJS文件时,首先触发的是install事件,进行安装。安装的过程就是将指定的一些静态资源进行离线缓存。下面是我的sw.js文件中的安装代码:

var CACHE_VERSION = ‘sw_v8’;

var CACHE_FILES = [

‘/js/jquery/min.js’,

‘/js/zui/min.js’,

‘/js/chanzhi.js’,

];

self.addEventListener(‘install’, function {

event.waitUntil(

caches.open(CACHE_VERSION)

.then(cache => cache.addAll(CACHE_FILES)

));

});

当安装成功后,serviceworker就会激活,这时就会处理 activate 事件回调
(提供了更新缓存策略的机会)。并可以处理功能性的事件 fetch 、sync 、push

self.addEventListener(‘activate’, function {

event.waitUntil(

caches.keys().then(function{

return Promise.all(keys.map(function{

if(key !== CACHE_VERSION){

return caches.delete;

}

}));

})

);

});

开发者工具

Chrome浏览器提供了一系列的工具来帮助您来调试Service
Worker,日志也会直接显示在控制台上。

您最好使用匿名模式来进行开发工作,这样可以排除缓存对开发的干扰。

最后,Chrome的Lighthouse扩展也可以为您的渐进式Web应用提供一些改进信息。

关于PWA

PWA(Progressive Web App),
即渐进式web应用。PWA本质上是web应用,目的是通过多项新技术,在安全、性能、体验等方面给用户原生应用的体验。而且无需像原生应用那样繁琐的下载、安装、升级等操作。

这里解释下概念中的“渐进式”,意思是这个web应用还在不断地进步中。因为目前而言,PWA还没有成熟到一蹴而就的程度,想在安全、性能、体验上达到原生应用的效果还是有很多的提升空间的。一方面是构建PWA的成本问题,另一方面是目前各大浏览器、安卓和IOS系统对于PWA的支持和兼容性还有待提高。

本文我将从网站缓存、http请求拦截、推送到主屏等功能,结合实例操作,一步步引领大家快速玩转PWA技术。

第一步:使用HTTPS

渐进式Web应用程序需要使用HTTPS连接。虽然使用HTTPS会让您服务器的开销变多,但使用HTTPS可以让您的网站变得更安全,HTTPS网站在Google上的排名也会更靠前。

由于Chrome浏览器会默认将localhost以及127.x.x.x地址视为测试地址,所以在本示例中您并不需要开启HTTPS。另外,出于调试目的,您可以在启动Chrome浏览器的时候使用以下参数来关闭其对网站HTTPS的检查:

  • 463.com,–user-data-dir
  • –unsafety-treat-insecure-origin-as-secure

小结

PWA技术正被广大企业及开发者们关注,虽然目前各设备的支持兼容有待提高,但这些都正在不断的改善进步。我也相信在不久的将来,PWA技术会逐步广泛普及,为广大企业和用户带来便利。本文和大家一起分享了PWA的相关技术与实例操作,后面还会就消息推送、数据同步等功能做进一步探讨交流。如果大家在学习PWA的过程中遇到其他问题,欢迎一起讨论交流。

第二步:创建一个应用程序清单(Manifest)

应用程序清单提供了和当前渐进式Web应用的相关信息,如:

  • 应用程序名
  • 描述
  • 所有图片(包括主屏幕图标,启动屏幕页面和用的图片或者网页上用的图片)

本质上讲,程序清单是页面上用到的图标和主题等资源的元数据。

程序清单是一个位于您应用根目录的JSON文件。该JSON文件返回时必须添加Content-Type: application/manifest+json 或者 Content-Type: application/jsonHTTP头信息。程序清单的文件名不限,在本文的示例代码中为manifest.json

{ “name” : “PWA Website”, “short_name” : “PWA”, “description” : “An
example PWA website”, “start_url” : “/”, “display” : “standalone”,
“orientation” : “any”, “background_color” : “#ACE”, “theme_color” :
“#ACE”, “icons”: [ { “src” : “/images/logo/logo072.png”, “sizes” :
“72×72”, “type” : “image/png” }, { “src” : “/images/logo/logo152.png”,
“sizes” : “152×152”, “type” : “image/png” }, { “src” :
“/images/logo/logo192.png”, “sizes” : “192×192”, “type” : “image/png” },
{ “src” : “/images/logo/logo256.png”, “sizes” : “256×256”, “type” :
“image/png” }, { “src” : “/images/logo/logo512.png”, “sizes” :
“512×512”, “type” : “image/png” } ] }

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
30
31
32
33
34
35
36
37
{
  "name"              : "PWA Website",
  "short_name"        : "PWA",
  "description"       : "An example PWA website",
  "start_url"         : "/",
  "display"           : "standalone",
  "orientation"       : "any",
  "background_color"  : "#ACE",
  "theme_color"       : "#ACE",
  "icons": [
    {
      "src"           : "/images/logo/logo072.png",
      "sizes"         : "72×72",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo152.png",
      "sizes"         : "152×152",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo192.png",
      "sizes"         : "192×192",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo256.png",
      "sizes"         : "256×256",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo512.png",
      "sizes"         : "512×512",
      "type"          : "image/png"
    }
  ]
}

程序清单文件建立完之后,你需要在每个页面上引用该文件:

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

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

以下属性在程序清单中经常使用,介绍说明如下:

  • name: 用户看到的应用名称
  • short_name: 应用短名称。当显示应用名称的地方不够时,将使用该名称。
  • description: 应用描述。
  • start_url: 应用起始路径,相对路径,默认为/。
  • scope: URL范围。比如:如果您将“/app/”设置为URL范围时,这个应用就会一直在这个目录中。
  • background_color: 欢迎页面的背景颜色和浏览器的背景颜色(可选)
  • theme_color: 应用的主题颜色,一般都会和背景颜色一样。这个设置决定了应用如何显示。
  • orientation: 优先旋转方向,可选的值有:any, natural, landscape,
    landscape-primary, landscape-secondary, portrait, portrait-primary,
    and portrait-secondary
  • display: 显示方式——fullscreen(无Chrome),standalone(和原生应用一样),minimal-ui(最小的一套UI控件集)或者browser(最古老的使用浏览器标签显示)
  • icons: 一个包含所有图片的数组。该数组中每个元素包含了图片的URL,大小和类型。

添加到主屏

PWA支持将web应用在主屏桌面上添加一个快捷方式,以方便用户快速访问,同时提升web应用重复访问的几率。你也许会说,现在移动端上的浏览器功能列表里一般都提供了“添加到桌面”的功能呀,但是PWA与浏览器自带的添加到桌面的实现方式不同。

PWA不需要用户刻意去功能列表中使用这个功能按钮,而是在用户访问web应用时,直接在界面中提示一个添加到主屏桌面的横幅,从web应用角度而言,这其实就是主动与被动的区别。

PWA实现该功能非常简单,只需要一个manifest.json文件,文件中用户可以自定义应用的启动页面、模板颜色、图标等内容。下面是我的manifest.json文件设置,大家可作参考:

{

“short_name”: “蝉知资源站”,

“name”: “蝉知资源站”,

“icons”: [

{

“src”: “chanzhiicon.png”,

“type”: “image/png”,

“sizes”: “48×48”

},

{

“src”: “192.png”,

“type”: “image/png”,

“sizes”: “192×192”

},

{

“src”: “512.png”,

“type”: “image/png”,

“sizes”: “512×512”

},

{

“src”: “144.png”,

“type”: “image/png”,

“sizes”: “144×144”

}

],

“start_url”: “/index.html”,

“display”: “standalone”,

“background_color”: “#2196F3”,

“orientation”: “landscape”,

“theme_color”: “#2196F3”

}

需要提醒的是,目前移动端IOS系统的支持并不好,安卓手机上须使用57版本以上的谷歌浏览器可以支持该功能,下面是我在安卓手机上的操作演示:

463.com 5添加到主屏

缓存刷新

示例代码中在发起请求之前会先查询缓存。当用户处于离线状态时,这很好,但是如果用户处于在线状态,那他只会浏览到比较老旧的页面。

各种资源比如图片和视频不会改变,所以一般都把这些静态资源设置为长期缓存。这些资源可以直接缓存一年(31,536,000秒)。在HTTP
Header中,就是:

Cache-Control: max-age=31536000

1
Cache-Control: max-age=31536000

页面,CSS和脚本文件可能变化的更频繁一些,所以你可以设置一个比较小的缓存超时时间(24小时),并确保在用户网络连接恢复时再次从服务器请求:

Cache-Control: must-revalidate, max-age=86400

1
Cache-Control: must-revalidate, max-age=86400

你也可以在每次网站发布时,通过改名的方式强制浏览器重新请求资源。

相关文章