1.什么是PWA?
渐进式网络应用(PWA)
是谷歌在2015年底提出的概念。基本上算是web应用程序,但在外观和感觉上与原生app
类似。支持PWA
的网站可以提供脱机工作、推送通知和设备硬件访问等功能。
2.PWA有那些优点?
- 更小更快: 渐进式的web应用程序比原生应用程序小得多。他们甚至不需要安装。这是他们没有浪费磁盘空间和加载速度非常快。
- 响应式界面:
PWA
支持的网页能够自动适应各种屏幕大小。它可以是手机、平板、台式机或笔记本
。 - 无需更新: 大多数移动应用程序需要每周定期更新。与普通网站一样,每当用户交互发生且不需要应用程序或游戏商店批准时,PWA总是加载最新更新版本。
- 高性价比:原生移动应用需要分别为
Android和iOS设备
开发,开发成本非常高。另一方面,PWAs
有着相同的功能,但只是先前价格的一小部分,开发成本低。 - SEO优势:搜索引擎可以发现
PWAs
,并且加载速度非常快。就像其他网站一样,它们的链接也可以共享。提供良好的用户体验和结果,在SEO排名提高。 - 脱机功能:由于
service worker API
的支持,可以在脱机或低internet连接
中访问PWAs
。 - 安全性:
PWAs
通过HTTPS
连接传递,并在每次交互中保护用户数据。 - 推送通知:通过推送通知的支持,
PWAs
轻松地与用户进行交互,提供非常棒的用户体验。 - 绕过应用商店:
原生app
如果需要任何新的更新,需要应用商店几天的审批,且有被拒绝或禁止的可能性,对于这方面来说,PWAs有它独特的优势,不需要App Store
支持。更新版本可以直接从web服务器加载,无需App Store
批准。 - 零安装:在浏览过程中,
PWA
会在手机和平板电脑上有自己的图标,就像移动应用程序一样,但不需要经过冗长的安装过程。
3.pwa缓存的原理
为什么能实现缓存或者叫离线存储?核心就是利用浏览器service-worker另启一个线程,这个线程负责去监听所有https请求(注意是https),当发现某些资源是需要缓存下来的他会把资源拉取到浏览器本地,访问的时候拦截请求,不走网络请求,直接读取本地资源。这样资源相当于都是用户本地的资源,响应速度肯定飞快,还有就是资源都在用户浏览器里面,就算断了网,资源也都是能正常访问。
pwa缓存的提速效果是非常明显,能保证你的页面在弱网环境下秒开,资源大部分都是在50毫秒左右的的响应时间。我们在safari浏览器测试的响应时间更加快速,基本都是在15ms左右!!!
4.PWA关键技术
- Service Worker (可以理解为服务工厂)
- Manifest (应用清单)
- Push Notification(推送通知)
5.PWA代码初探
看来上面的介绍,是不是跃跃欲试呢?接下来将用代码来简单使用一下service worker,缓存页面中的css、js文件,具体例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="/cache1.css">
<title>pwa</title>
</head>
<body>
<div id="app">test1</div>
<!-- built files will be auto injected -->
<script src='/cache1.js'></script>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js').then((registration) => {
console.log('Service Worker Registration')
}, (err) => {
console.log(err)
})
})
}
self.addEventListener('fetch', () => {
console.log('ss')
})
</script>
</body>
</html>
sw.js:
var cacheName = 'my-cache'
var cacheList = ['/cache1.css', '/cache1.js']
self.addEventListener('install', function(event) {
event.waitUntil(
// 安装成功后向caches中存入需要缓存的文件
caches.open(cacheName).then(function (cache) {
return cache.addAll(cacheList)
})
)
});
// 监听service worker fetch
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// 在缓存中查找到匹配的请求,就从缓存返回
if (response) {
console.log(response)
return response;
}
// 缓存中没有查找到对应请求,继续网络请求
return fetch(event.request);
}
)
);
})
如上例所示,利用service worker缓存了页面请求中cache1.js、cache1.css,然后再刷新一下网页,网页请求就会变成下图这样:
6.可以使用webpack打包技术将service worker引入项目当中
A. 创建文件
B. 下载安装包
npm install --save-dev workbox-webpack-plugin
C. 修改配置文件
在webpack.config.js文件当中配置:
plugins: [
new WorkboxWebpackPlugin.GenerateSW({
/*
1. 帮助serviceworker快速启动
2. 删除旧的 serviceworker
生成一个 serviceworker 配置文件~
*/
clientsClaim: true,
skipWaiting: true
})
]
在index.html当中要配置:
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/service-worker.js')
.then(() => {
console.log('sw注册成功了~');
})
.catch(() => {
console.log('sw注册失败了~');
});
});
}
</script>
要注意一下package.json文件的配置也要进行更改
1. eslint不认识 window、navigator全局变量
解决:需要修改package.json中eslintConfig配置
"env": {
"browser": true // 支持浏览器端全局变量
}
2. sw代码必须运行在服务器上
--> nodejs
-->npm i serve -g
serve -s build 启动服务器,将build目录下所有资源作为静态资源暴露出去