我正在处理一个单页PWA,需要使所有内容都可以脱机使用。
初始设置和问题:我使用create-react-app设置了基础知识,然后使用react-app-rewired用InjectManifest替换了GenerateSW插件,并在我的服务工作者中对webpack生成的清单进行了一个简单的precacheAndRoute。
除了我的mp3文件外,它的工作原理像一个咒语:在Safari中,我看不到曲目的持续时间,进度条已消失。在Chrome中或多或少都可以,唯一的问题是播放音频文件时会中断最后的1-2秒。
初始解决方案:在我的SW配置中,我为mp3-文件添加了一个特定的registerRoute,该文件使用了根据https://developers.google.com/web/tools/workbox/guides/advanced-recipes#cached-av使用范围请求插件。一切正常,现在只要我在线,一切都可以在Chrome和Safari中正常运行。当我离线时,可以从缓存中获取除mp3文件以外的所有内容。
您可以看到她的错误:https://cgl-hunter-kids-test.firebaseapp.com/单击标题图像进入站点,在左上方菜单中选择“历史记录”,然后选择9个可用故事中的任何一个。音频播放器在右上角。
在Chrome开发工具中,我可以看到它在线时会从Service Worker中提取mp3文件。我还可以看到mp3文件确实存在于预缓存中。我不知道为什么离线时找不到它们-有人可以帮忙吗?
谢谢,戴安娜
我的服务工作者配置:
const COOKIE_CONSENT_ENDPOINT = '/hunterkidsCookieConsent';
const GAME_DATA_ENDPOINT = '/hunterkidsGameData';
/* Use client claim to handle SW updates */
workbox.core.clientsClaim();
/* Activate new SW (user triggered) */
self.addEventListener('message', (event) => {
if (event.data.action === 'skipWaiting') self.skipWaiting();
});
/* Cache files from _precacheManifest (generated by InjectManifest webpack plugin) */
self.__precacheManifest = [].concat(self.__precacheManifest || []);
self.addEventListener('activate', (event) => {event.waitUntil(clients.claim());});
/* Handle ranged quests of mp3 files */
// https://github.com/GoogleChrome/workbox/issues/1644
// https://developers.google.com/web/tools/workbox/guides/advanced-recipes#cached-av
workbox.routing.registerRoute(
({url}) => url.pathname.endsWith('.mp3'),
new workbox.strategies.CacheFirst({
cacheName: workbox.core.cacheNames.precache,
plugins: [
new workbox.cacheableResponse.Plugin({ statuses: [200] }),
new workbox.rangeRequests.Plugin(),
],
})
);
/* Special fetch requests */
self.addEventListener('fetch', function(event) {
const {
request,
request: {url, method},
} = event;
/* Game progress */
if (url.match(GAME_DATA_ENDPOINT)) {
if (method === 'POST') {
/* Write data to cache */
request.json().then(body => {
caches.open(GAME_DATA_ENDPOINT).then(function(cache) {
cache.put(GAME_DATA_ENDPOINT, new Response(JSON.stringify(body)));
});
});
return new Response('{}');
} else {
/* Read data from cache */
event.respondWith(
caches.open(GAME_DATA_ENDPOINT).then(function(cache) {
return cache.match(GAME_DATA_ENDPOINT).then(function (response) {
return response || new Response('{}');;
}) || new Response('{}');
})
);
}
}
/* Cookie consent */
if (url.match(COOKIE_CONSENT_ENDPOINT)) {
if (method === 'POST') {
/* Write data to cookie */
request.json().then(body => {
caches.open(COOKIE_CONSENT_ENDPOINT).then(function(cache) {
cache.put(COOKIE_CONSENT_ENDPOINT, new Response(JSON.stringify(body)));
});
});
return new Response('{}');
} else {
/* Read data from cookie */
event.respondWith(
caches.open(COOKIE_CONSENT_ENDPOINT).then(function(cache) {
return cache.match(COOKIE_CONSENT_ENDPOINT).then(function (response) {
return response || new Response('{}');;
}) || new Response('{}');
})
);
}
}
});
/* All other requests */
workbox.precaching.precacheAndRoute(self.__precacheManifest || []);
我知道了!
我必须在registerRoute中将matchOptions添加到CacheFirst策略:
workbox.routing.registerRoute(
({url}) => url.pathname.endsWith('.mp3'),
new workbox.strategies.CacheFirst({
cacheName: workbox.core.cacheNames.precache,
plugins: [
new workbox.cacheableResponse.Plugin({ statuses: [200] }),
new workbox.rangeRequests.Plugin(),
],
matchOptions: {
ignoreSearch: true,
ignoreVary: true
}
})
);
可能与使用Firebase进行托管有关,但我不确定。