workbox-webpack-plugin创建pwa
PWA(Progressive Web Apps)是⾕歌近⼏年⼀直在推进的 web 应⽤新模型。PWA 借助 Service Worker 缓存⽹站的静态资源,甚⾄是⽹络请求,使⽹站在离线时也能访问。并且我们能够为⽹站指定⼀个图标添加在⼿机桌⾯,实现点击桌⾯图标即可访问⽹站。
Web App Manifest是⼀个JSON⽂件,它⽤来定义⽹站添加到桌⾯的图标以及从桌⾯图标进⼊⽹站时的⼀系列⾏为,如:启动样式,全屏主题等。
先创建manifest.json:
{
"name": "blog-pwa",
"short_name": "blog-pwa",
"icons": [
{
"src": "/img/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/img/icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/index.html",
"display": "standalone",
"background_color": "#000000",
"theme_color": "#4DBA87"
}
将⽂件引⼊:
<link rel=manifest href=/manifest.json>
我们可以从开发者⼯具上看我们的配置:
icons属性定义了添加到桌⾯的图标,display: standalone表⽰我们要从桌⾯全屏启动,theme_color": "#4DBA87是全屏启动时⼿机顶部状态栏的背景⾊,background_color": "#000000是启动页的背景⾊,启动页⽬前不能定制,默认由background_color加icon加name组合⽽成。
Web App Manifest很简单,只要照着⽂档每个属性看⼀遍就⾏。
Service Worker是浏览器在后台独⽴于⽹页运⾏的脚本。是它让 PWA 拥有极快的访问速度和离线运⾏能⼒。
那它是如何做到的呢?我们⼀步步来看。
注册Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/service-worker.js')
.then(registration => {
console.log(
'ServiceWorker registration successful with scope: ',
registration.scope
)
})
.catch(err => {
console.log('ServiceWorker registration failed: ', err)
})
}
需要注意的是,Service Worker脚本除了域名为localhost时能运⾏在http协议下以外,只能运⾏https协议下。
安装
const CACHE_NAME = 'cache-v1'
const DATA_CACHE_NAME = 'data-cache-v1'
const PRE_CACHE = ['/index.html', '/css/app.css', '/js/app.js']
self.addEventListener('install', e => {
console.log('[ServiceWorker] Install')
e.waitUntil(
caches.open(CACHE_NAME).then(cache => {
return cache.addAll(PRE_CACHE)
})
)
})
在安装的时候预缓存⽹站的静态资源,任何资源路径出错都会造成Service Worker安装失败。
代理请求
self.addEventListener('fetch', e => {
caches.quest).then(response => {
if (response) {
return response
}
const fetchRequest = e.request.clone()
return fetch(fetchRequest).then(response => {
// Check if we received a valid response
if (!response || response.status !== 200) {
return response
}
cacheableconst responseToCache = response.clone()
caches.open(DATA_CACHE_NAME).then(cache => {
cache.quest, responseToCache)
})
return response
})
})
)
})
安装成功后,Service Worker就可以监听⽹站的所有请求,匹配到缓存时直接返回,未匹配到时请求服务器,服务器成功返回时添加到缓存。更新
现在⽹站的Service Worker已经可以正常⼯作了,那如何更新它呢?
我们只需要修改Service Worker⽂件就可以更新它。当我们每次访问⽹站时都会去下载这个⽂件,当发现⽂件不⼀致时,就会安装这个
新Service Worker,安装成功后,它将进⼊等待阶段。当我们关闭窗⼝重新导航到⽹站时(刷新⽹页不⾏),新Service Worker将开始控制⽹站。旧Service Worker终⽌⼯作并触发activate事件:
self.addEventListener('activate', e => {
e.waitUntil(
caches.keys().then(keyList => {
return Promise.all(
keyList.map(key => {
if (key !== CACHE_NAME && key !== DATA_CACHE_NAME) {
console.log('[ServiceWorker] Removing old cache', key)
return caches.delete(key)
}
})
)
})
)
})
在其卸载时⼀定要删除旧缓存,不然我们的⽹站永远⽆法更新。
上⾯只简单讲了Service Worker如何⼯作。我们会发现有很多问题需要我们进⼀步解决:
1. 预缓存的静态资源修改后在下⼀次发版本时的⽂件名都不⼀样,⼿动写死太低效,最好每次都⾃动⽣成资源⽂件名。
2. 缓存资源是以硬编码字符串判断是否有效,这样每次发版本都需要⼿动修改,才能更新缓存。并且每次都是全量更新。能否以⽂件的
粒度进⾏资源缓存呢?
3. 请求代理没有区分静态资源和动态接⼝。已经缓存的动态接⼝也会⼀直返回缓存,⽆法请求新数据。
上⾯只列出了三个明显的问题,还有很多问题是没有考虑到的。如果让我们⾃⼰来解决这些问题,不仅是⼯作量很⼤,⽽且也很难写出⽣产环境可⽤的Service Worker。
既然如此,我们最好是站在巨⼈的肩膀上,这个巨⼈就是⾕歌。workbox 是由⾕歌浏览器团队发布,⽤来协助创建 PWA 应⽤
的JavaScript库。当然直接⽤workbox还是太复杂了,⾕歌还很贴⼼的发布了⼀个webpack插件,能够⾃动⽣成Service Worker和静态资源列表- 。
只需简单⼀步就能⽣成⽣产环境可⽤的Service Worker:
const { GenerateSW } = require('workbox-webpack-plugin')
new GenerateSW()
打包⼀下:
还能说什么呢?⾕歌⼤法好!当然这只是最简单的可⽤版本,其实这⾥有⼀个最严重的问题不知道有没⼈发现,那就是importScripts引⽤的是⾕歌域名下的 cdn ,这让我们墙内的⽹站怎么⽤,所以我们需要把这个问题解决并⾃定义⼀些配置增强Service Worker的能⼒:
new GenerateSW({
importWorkboxFrom: 'local',
skipWaiting: true,
clientsClaim: true,
runtimeCaching: [
{
// To match cross-origin requests, use a RegExp that matches
// the start of the origin:
urlPattern: new RegExp('^api'),
handler: 'staleWhileRevalidate',
options: {
// Configure which responses are considered cacheable.
cacheableResponse: {
statuses: [200]
}
}
},
{
urlPattern: new RegExp('^cdn'),
// Apply a network-first strategy.
handler: 'networkFirst',
options: {
// Fall back to the cache after 2 seconds.
networkTimeoutSeconds: 2,
cacheableResponse: {
statuses: [200]
}
}
}
]
})
⾸先importWorkboxFrom我们指定从本地引⼊,这样插件就会将workbox所有源⽂件下载到本地,墙内开发者的福⾳。上⾯提到过新Service Worker安装成功后需要进⼊等待阶段,skipWaiting: true将使其跳过等待,安装成功后⽴即接管⽹站,注意这个要和clientsClaim⼀起设置
为true。runtimeCaching顾名思义是配置运⾏时如何缓存请求的,这⾥只说⼀点,缓存跨域请求时urlPattern的值必须为^开头的正则表达式,其它的配置看⽂档都能得到详细的介绍。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。