原文链接: PWA 改造已有项目
在已有项目中使用pwa
只需要在index.html 中注册 引入注册脚本和manifest.json
manifest.json
{
"name": "fast-style",
"short_name": "fast-style",
"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"
}
registerServiceWorker.js
if ("serviceWorker" in navigator) {
window.addEventListener("load", function() {
console.log("registerServiceWorker.js");
navigator.serviceWorker.register("./service-worker.js").then(
function(registration) {
console.log(
"ServiceWorker registration successful with scope: ",
registration.scope
);
},
function(err) {
console.log("ServiceWorker registration failed: ", err);
}
);
});
}
service-worker.js
需要对url做校验,
github 有时会自动请求这样的东西...
// chrome-extension://jdbnofccmhefkmjbkkdkfiicjkgofkdh/img/icon-bookmark.svg
console.log("service-worker.js");
self.addEventListener("install", function (event) {
console.log("install");
});
const CACHE_NAME = "cache-v1"
let immutableData = new Set(
[
"/",
"/css",
"/js",
"/img",
"/style_image",
"/style_model",
]
)
let mutableData = new Set(
[]
)
const HOST = "github"
self.addEventListener("install", function (event) {
// Perform install steps
console.log("install");
self.skipWaiting()
});
self.addEventListener("fetch", event => {
// console.log('event', event)
let url = new URL(event.request.url)
// 缓存策略过滤
if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') {
console.log("url cached", url, event)
return
}
// 本地域名过滤,只缓存自己域名下的文件
if (!url.host.includes(HOST) ||
!url.href ||
!url.href.startsWith("http") ||
!url.href.startsWith("https")) {
console.log("url", url, event)
event.respondWith(fetch(event.request))
return
}
// url 过滤, 确保herf存在,并且是域名下
// 避免加载chrome的拓展出现的问题
if (url.host.includes(HOST))
event.respondWith(
caches.open(CACHE_NAME).then(cache =>
cache.match(event.request).then(cacheResponse => {
let fetchPromise = fetch(event.request).then(networkResponse => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return cacheResponse || fetchPromise;
})
)
);
});
sw.js 设置缓存策略和更新策略的另外实现
console.log("service-worker.js");
// 一个网站可以设置多个版本的缓存
let CACHE_NAME = "my-site-cache-v1";
// let urlsToCache = ["/", "/styles/main.css", "/script/main.js"];
// let urlsToCache = ["/index.html","/js/*", "/css/*", "/img/*", "/style_image/*", "/style_model/*"];
let urlsToCache = ["/", "/js/", "/css/", "/img/", "/style_image/", "/style_model/"];
// let urlsToCache = ['/style_image/candy.jpg','/js/']
self.addEventListener("install", function (event) {
// Perform install steps
event.waitUntil(
// open 会打开缓存并返回,如果没有就创建
caches.open(CACHE_NAME).then(function (cache) {
console.log("Opened cache");
return cache.addAll(urlsToCache);
})
);
});
// 浏览器缓存问题
// 如果文件设置缓存为一个月,即使在sw中添加到cache中
// 当重新使用fetch获取最新的文件时,依然会是旧的版本
self.addEventListener("fetch", function (event) {
// console.log('fetch ', event, event.request.url)
event.respondWith(
// match在缓存中寻找资源,无论是否找到都会返回
// 不会被reject,所以需要自己判断是否找到
// 找到后就返回缓存,没有找到就重新下载
// 忽略查询参数 /a?s=1和/a?v=2 是一样的
// 默认两个url是不一样的
// caches.match(event.request,{ignoreSearch:true})
caches.match(event.request).then(function (response) {
// Cache hit - return response
if (response) {
return response;
}
// 没有缓存则重新请求,如果请求失败,返回失败消息
return fetch(event.request).then(
response => response
).catch(
// 如果请求的是网页, 并且没有找到, 返回失败消息
() => event.request.headers.get('accept').includes('text/html') || caches.match('/index-offline.html')
)
// return fetch(event.request);
})
);
});
self.addEventListener("activate", function (event) {
console.log("activate", event);
caches.keys().then(console.log);
event.waitUntil(
caches.keys().then(cacheNames =>
Promise.all(
cacheNames.map(cacheName => {
// 删除旧的缓存,避免删除新的缓存
if (
CACHE_NAME !== cacheName &&
cacheName.startsWith("my-cache-old-v1")
)
return caches.delete(cacheName);
})
)
)
);
});