原文转载自「刘悦的技术博客」https://v3u.cn/a_id_216

PWA(Progressive web apps,渐进式 Web 应用)使用现代的 Web API 以及传统的渐进式增强策略来创建跨平台 Web 应用程序,说白了,PWA可以让我们的站点以原生APP的形式运行,但相比于安装原生APP应用,访问PWA显然更加容易和迅速,还可以通过链接来分享PWA应用。

有许多知名的网络平台已经将 PWA 方案落地,比如Twitter。选择增强的网站体验而不是原生应用。事实上使用PWA也确实从中获得了显而易见的益处。https://www.pwastats.com 这个网站上分享了许多案例研究,PWA相比于传统应用有以下好处:

1、减少应用安装后的加载时间,通过 Service Workers 来进行缓存,以此来节省带宽和时间。

2、当应用有可用的更新时,可以只更新发生改变的那部分内容。相比之下,对于一个原生应用而言,即便是最微小的改动也需要强制用户去进行热更新或者再次下载整个应用。
3、外观和使用感受与原生平台更加融为一体——应用图标被放置在主屏幕上,应用可以全屏运行等。
凭借系统通知和推送消息与用户保持连接,对用户产生更多的吸引力,并且提高转换效率。

诚然,从零开始研发PWA应用会有一定的成本,但如果我们本身就拥有基于Web的站点,那么就可以通过增加对应的配置文件和服务进行升级操作,直接拥有PWA应用。

HTTPS服务

首先PWA要求站点的请求方式为HTTPS,如果是生产环境,可以通过为Nginx服务器配置SSL的方式进行适配,但是线下环境测试PWA时就有点费劲了,所以通过openssl工具为本地域名localhost做自签证书:

openssl req -x509 -out localhost.crt -keyout localhost.key \
-newkey rsa:2048 -nodes -sha256 \
-days 3650 \
-subj '/CN=localhost' -extensions EXT -config <( \
printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

产出:localhost.crt和localhost.key文件,key是私用密钥openssl格式,通常是rsa算法。csr是证书请求文件,用于申请证书,在制作csr文件的时,必须使用自己的私钥来签署申,还可以设定一个密钥。

将文件放到项目的根目录下,随后在构建项目服务的时候配置即可,以Tornado为例:

server = httpserver.HTTPServer(app,xheaders=True,ssl_options={
"certfile": "./localhost.crt",
"keyfile": "./localhost.key",
}) # 指定端口
server.listen(443)

这里通过设置ssl_options参数来导入私钥和证书,同时将端口改为HTTPS默认端口号443。如此,在本地也可以对PWA进行测试了,当然了,如果不需要本地操作,也可以跳过这步。

manifest.json配置文件

为了实现 PWA 应用添加至桌面的功能,除了要求站点支持 HTTPS 之外,还需要准备 manifest.json 文件去配置应用的图标、名称等信息。

以本站为例,在站点根目录创建manifest.json文件:

{
"name": "刘悦的技术博客",
"short_name": "刘悦的技术博客",
"description": "刘悦的技术博客",
"icons": [
{
"src": "https://v3u.cn/v3u/Public/images/pwa192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "https://v3u.cn/v3u/Public/images/pwa512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"background_color": "#FFF",
"theme_color": "#FFF",
"display": "standalone",
"orientation": "portrait",
"start_url": "/",
"scope": "/"
}

由上至下,依次是 PWA 应用的名称、描述、图标文件、banner颜色、显示方式、开始页面的链接和 PWA 的作用域。为此我们需要提供两张不同分辨率的站点图标文件:

ServiceWorker服务

Service Worker是一个注册在指定源和路径下的事件驱动型Web Worker。它充当了Web应用程序与浏览器之间的代理服务器,进行资源在文件级别下的缓存与操控,拦截页面请求,实现在不同的情况下对不同请求的响应策略。

Service Worker本质上就是一个Web Worker,因此它具有Web Worker的特点:无法操作DOM、脱离主线程、独立上下文。

Service Worker还具有这些特点:只能在Https下使用、运行在浏览器后台,不受页面刷新影响、更强大的离线缓存能力(使用Cache API)、请求拦截能力、完全异步,不能使用同步API、持续运行,第一次访问页面后,Service Worker就会安装激活并持续运行,直到手动销毁。

以本站为例,在站点根目录创建sw.js文件,注意Service Worker文件位置一定得在根目录,如果不在根目录也要通过重写或者url映射让其可以通过根目录路径进行访问,如:https://v3u.cn/sw.js,否则浏览器会检测不到Service Worker服务:

var CACHE_NAME = 'v3u-cache-v1';
var urlsToCache = [
'/',
'/v3u/Public/css/tidy_min.css'
]; self.addEventListener('install', function (event) {
event.waitUntil(
caches.open(CACHE_NAME).then(function (cache) {
console.log('Open cache');
return cache.addAll(urlsToCache);
}).then(function () {
self.skipWaiting();
})
);
});

当我们为页面注册Service Worker后,Service Worker开始进行安装,安装成功之后,会在worker中触发install事件;如果安装失败,则进入废弃状态。

如果Service Worker逻辑文件更新(相关资源文件变动或者内部逻辑更新等),Service Worker会重新安装,如果这个时候,页面依然存在激活状态下的worker(旧的Service Worker),那么新的worker会进入waiting状态进行等待,直到我们主动去操作worker强制其更新,或者等待用户关闭所有页面,这个时候新的worker才会进入到激活状态。

在install事件中,我们使用caches.open方法打开cache对象,并通过cache.addAll缓存所有我们列出的文件。如果Service Worker存在更新,我们使用skipWaiting跳过等待,直接强制新的worker进入激活状态。

随后,添加fetch事件:

self.addEventListener('fetch', function(event){
if(event.request.method !== 'GET') return;
event.respondWith(
caches.match(event.request).then(function(response){
if(response){
console.log('return caches');
return response;
}else{
return fetch(event.request).catch(function(){
if(/\.html$/.test(event.request.url))
return caches.match('/html/neterror.html');
});
}
})
)
});

这里只监听了全站的GET请求方式,即我们只希望控制资源请求。通过caches.match检查请求是否命中了缓存,如果命中,则直接返回缓存给用户,防止重复请求,节约资源。如果没有命中,则将使用fetch方法请求网络资源并返回给用户。当网络状态异常时(fetch().catch()),返回404页面的缓存给用户,告知用户当前处于无网络状态,不能访问相关页面。指定了一些页面和文件进行缓存,我们希望用户在无网络的情况下只能访问到我们指定缓存的页面。

当然,还有另外一种情况,我们指定了一些页面进行缓存(常用页面),当用户访问到一些不常用页面时,再对其进行缓存。这样,我们可以对资源配置进行优化,不过多的占用用户本地资源去缓存所有页面,因为PWA的缓冲本身是存储到客户端的,对于非所有用户的常用页面,按需缓存:

self.addEventListener('fetch', function(event){
if(event.request.method !== 'GET') return;
event.respondWith(
caches.match(event.request).then(function(response){
if(response){
console.log('return caches');
return response;
}else{
return fetch(event.request).then(function(res){
var responseToCache = res.clone();
caches.open(CACHE_NAME).then(function(cache){
catch.put(event.request, responseToCache);
})
return res;
}); }
})
)
});

至此,ServiceWorker服务文件就撰写完成了。

生产环境上线配置:

分别将manifest.json和sw.js文件分别上传到生产环境之后,在页面的head标签中进行声明:

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

声明后,注意访问一下是否正确返回:https://v3u.cn/manifest.json

随后在页面中注册Service Worker服务:

<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () =>
navigator.serviceWorker.register("/sw.js?v0")
.catch(() => {}) // ignore
);
}
</script>

这里首先判断当前浏览器的navigator是否支持serviceWorker,随后使用navigator.serviceWorker.register函数来注册Service Worker。其中,参数为要执行的worker逻辑文件路径,注意这个路径是基于origin的,而非当前文件。

接着键入组合键,打开chrome浏览器的开发者工具:

Mac系统上的“⌥+⌘+I”

Win系统上的“F12+Ctrl+Shift+I”

在Chrome 的应用标签下进行检查,看应用清单有没有读出你的 PWA 应用信息配置文件:

随后在serviceWorker标签下检查serviceWorker是否正确运行:

接着访问站点,在地址栏即可添加PWA应用:

访问效果:

结语

渐进式增强和响应式设计已经可以让我们构建对移动端非常友好的站点,而PWA则又在我们的身后轻轻地推了一把,黄河之水源可滥觞,星星之火正在燎原,一年以内,我们都将感到PWA的灼人温度。

原文转载自「刘悦的技术博客」 https://v3u.cn/a_id_216

天人合一物我相融,站点升级渐进式Web应用PWA(Progressive Web Apps)实践的更多相关文章

  1. PWA(Progressive Web App)入门系列:(一)PWA简单介绍

    前言 PWA做为一门Google推出的WEB端的新技术,长处不言而喻.但眼下对于相关方面的知识不是非常丰富.这里我推出一下这方面的新手教程系列.提供PWA方面学习. 什么是PWA PWA全称Progr ...

  2. 关于PWA ( Progressive web apps )

    渐进式Web应用程序使用现代Web API以及传统的渐进式增强策略来创建跨平台Web应用程序.这些应用程序无处不在,并提供多种功能,使其具有与本机应用程序相同的用户体验优势.这套文档告诉您需要了解的所 ...

  3. Progressive web app理念及发展前景

    前一段时间微信推出微信小程序进行公测,着实火了一把,博得了大众的眼球,不明真相的吃瓜观众们纷纷围观,所谓的“微信小程序”,通俗的讲就是一种不需要下载安装即可使用的应用程序,脱离于app商店依托于浏览器 ...

  4. 试着给VuePress添加渐进式Web应用(PWA)支持,基于vuepress/plugin-pwa,点亮离线访问

    背景 有时候,我们也希望VuePress构建的文档中心能支持离线访问,这时候我们需要给他添加渐进式Web应用(PWA,Progressive Web App)的支持,根据官方文档指引,我们可以借助插件 ...

  5. (转)PWA(Progressive Web App)渐进式Web应用程序

    PWA 编辑 讨论 PWA(Progressive Web App)是一种理念,使用多种技术来增强web app的功能,可以让网站的体验变得更好,能够模拟一些原生功能,比如通知推送.在移动端利用标准化 ...

  6. PWA(Progressive web apps),渐进式 Web 应用

    学习博客:https://www.jianshu.com/p/098af61bbe04 学习博客:https://www.zhihu.com/question/59108831 官方文档:https: ...

  7. Web应用托管服务(Web+)隐藏的十个上云最佳姿势

    随着云计算浪潮的推进,技术架构云化已经成为大势所趋.特别是最近由CNCF推动的云原生概念,将符合云原生标准的各种开源技术方案推向了前所未有的高度.在这一波浪潮的推动下,越来越多的企业开始了自身的数字化 ...

  8. Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问

    本篇内容还是建立在上一篇Java Web学习系列——Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Jar包 这 ...

  9. 转 web项目中的web.xml元素解析

    转 web项目中的web.xml元素解析 发表于1年前(2014-11-26 15:45)   阅读(497) | 评论(0) 16人收藏此文章, 我要收藏 赞0 上海源创会5月15日与你相约[玫瑰里 ...

随机推荐

  1. unity---判断物体碰撞的对象

    脚本效果 trrn对象为地面,排除这个选项

  2. 搭建自己的个人web项目指南 ---(一)服务器购买与基础配置 | windows连接到自己的云服务器

    (一)服务器购买与基础配置 | windows连接到自己的云服务器 一.服务器选购指南 厂商选择 目前市面上提供服务器租用的厂商很多,比较知名的还是阿里云和腾讯云,两家的稳定性都非常不错,小伙伴们可以 ...

  3. 《C Primer Plus》第六版笔记--7~10章

    目录 第七章 C控制语句:分支和跳转 第八章 字符输入/输出和输入验证 第九章 函数 第十章 数组和指针 第七章 C控制语句:分支和跳转 if else 用法 if (expression) //ex ...

  4. 攻防世界pwn题:实时数据检测

    0x00:查看文件 一个32位的文件,canary.NX.PIE保护机制均关闭. 0x01:用IDA进行静态分析 程序很简单,输入一串字符(个数限制:512),然后再输出.最后根据key变量进行条件语 ...

  5. Python参数传递中的 args, kwargs

    概念 真正的Python参数传递语法是*和**,其被称为 被称为打包和解包参数.*args和**kwargs只是大家默认的一种形式.也可以写成*keys和**kkeys等其他形式.二者都是为了在不知道 ...

  6. 怎么理解相互独立事件?真的是没有任何关系的事件吗?《考研概率论学习之我见》 -by zobol

    1.从条件概率的定义来看独立事件的定义 2.从古典概率的定义来看独立事件的定义 3.P(A|B)和P(A)的关系是什么? 4.由P(AB)=P(A)P(B)推出"独立" 5.从韦恩 ...

  7. 为什么 C# 访问 null 字段会抛异常?

    一:背景 1. 一个有趣的话题 最近在看 硬件异常 相关知识,发现一个有意思的空引用异常问题,拿出来和大家分享一下,为了方便讲述,先上一段有问题的代码. namespace ConsoleApp2 { ...

  8. 华为云发布桌面IDE-CodeArts

    摘要:华为伙伴暨开发者大会2022,发布华为云桌面IDE-CodeArts. 本文分享自华为云社区<华为云发布桌面IDE-CodeArts,让连接更简单.编码更智能>,作者: Huawei ...

  9. linux系统健康检查脚本

    #!/bin/bash echo "You are logged in as `whoami`"; if [ `whoami` != root ]; then echo " ...

  10. docker 部署 minio

    1.下载镜像 docker pull minio/minio 2.启动 docker run -p 9000:9000 --name minio \ -d --restart=always \ -e ...