Это решение, которое я придумала, используя рабочий ящик Google .
Sidenote: Workbox, похоже, имеет решение для наиболее распространенных сценариев использования служащим и имеет очень гибкий дистрибутив модель, с которой довольно легко работать, либо в ванильной среде js, либо с выбранной вами структурой.
В итоге мы преобразовали наш серверный AppCache (код кэшированного манифеста) для создания работника сервиса. ( Как предварительно кэшировать список URL-адресов из файла json? )
В зависимости от языка на стороне сервера ваш код будет отличаться, но это конечный продукт, который работал для us:
service-worker. js (сгенерированный сервер)
const productVersion = "3.01";
importScripts('/assets/workbox/workbox-sw.js');
workbox.setConfig({
modulePathPrefix: '/assets/workbox/'
});
const { precacheAndRoute, createHandlerBoundToURL } = workbox.precaching;
const { NavigationRoute, registerRoute, setCatchHandler } = workbox.routing;
precacheAndRoute([
// cache index html
{url: '/', revision: '3.01' },
// web workers
{url: '/assets/some-worker.js?ver=3.01', revision: '' },
{url: '/assets/other-worker.js?ver=3.01', revision: '' },
// other js files
{url: '/assets/shared-function.js', revision: '3.01' },
// ... removed for brevity
// css
{url: '/assets/site.css', revision: '3.01' },
{url: '/assets/fonts/fonts.css', revision: '3.01' },
// svg's
{url: '/assets/images/icon.svg', revision: '3.01' },
{url: '/assets/images/icon-2.svg', revision: '3.01' },
// png's
{url: '/assets/images/img-1.png', revision: '3.01' },
{url: '/assets/images/favicon/apple-touch-icon-114x114.png', revision: '3.01' },
// ...
// ...
// fonts
{url: '/assets/fonts/lato-bla-webfont.eot', revision: '3.01' },
{url: '/assets/fonts/lato-bla-webfont.ttf', revision: '3.01' },
// sounds
{url: '/assets/sounds/keypress.ogg', revision: '3.01' },
{url: '/assets/sounds/sale.ogg', revision: '3.01' },
]);
// Routing for SPA
// This assumes DEFAULT_URL has been precached.
const DEFAULT_URL = '/';
const handler = createHandlerBoundToURL(DEFAULT_URL);
const navigationRoute = new NavigationRoute(handler, {
denylist: [
new RegExp('/ping'),
new RegExp('/upgrade'),
new RegExp('/cache.manifest'),
],
});
registerRoute(navigationRoute);
// This allows the main window to signal the service worker that
// it should go ahead and install if it's waiting.
addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
skipWaiting();
}
});
- Есть еще несколько вещей, на которые стоит обратить внимание. Нам пришлось выяснить, как плавно перейти с App? Cache на Service Workers. Оказывается, генерация пустого кеш-манифеста для нас сделала свое дело.
- У нас уже был процесс обновления (запрос пользователя на обновление или принудительное автоматическое обновление c с таймером обратного отсчета), поэтому нам пришлось проделать некоторую работу, чтобы заставить его работать с сервисными работниками. Обратите внимание, что конец файла рабочего сервиса имеет код
addEventListener
. Мы на самом деле называем это со страницы обновления, чтобы получить плавный процесс обновления. Это выглядит примерно так:
A) Сценарий обновления обнаруживает, что доступна новая версия (множество способов сделать это, опрос вызовов API и т. Д. c)
B) Если пользователь принимает или истекает таймер перенаправить пользователя на upgrade
страницу. Этот шаг очень важен, потому что / c вы не можете обновить работника сервиса, если приложение все еще работает. Перейдите на страницу обновления, подождите, пока сервисный работник установится, и скажите, чтобы он пропустил ожидание и перенаправил на главный экран (логин).
C) Пользователь с удовольствием запускает новую версию приложения.
Код страницы обновления: (это хорошая страница для отображения «обновляющего» пользовательского интерфейса какого-либо типа)
<script type="module">
import { Workbox } from '/assets/workbox/workbox-window.prod.mjs';
if ('serviceWorker' in navigator) {
const wb = new Workbox('/serviceworker');
// This code exists b/c a service worker can't update with just a refresh/reload in the
// browser. This is b/c on a reload, the old and new page exist simultaneously and the old MUST
// unload before the new service worker can automatically assume control. Also if multiple pages
// are open, this blocks the service worker from taking control (multiple pages should not an issue with this app).
// This code activates a waiting service worker and _then_ redirects back to the app.
// Add an event listener to detect when the registered
// service worker has installed but is waiting to activate.
wb.addEventListener('waiting', (event) => {
// Set up a listener that will reload the page as soon as the previously waiting
// service worker has taken control.
wb.addEventListener('controlling', (event) => {
window.location.replace('/login');
});
// Send a message telling the service worker to skip waiting.
// This will trigger the `controlling` event handler above.
wb.messageSW({type: 'SKIP_WAITING' });
});
wb.register();
}
// set a timeout in case the service worker has already installed.
setTimeout(function () {
window.location.replace('/login');
}, 30000);
</script>
Главная страница (индекс. html, et c) (Определяет, подходит ли пользователь к приложению с готовым к активации работником сервера, поэтому для загрузки нужных ресурсов / кода требуется refre sh)
<script type="module">
import { Workbox } from '/assets/workbox/workbox-window.prod.mjs';
if ('serviceWorker' in navigator) {
const wb = new Workbox('/serviceworker');
wb.addEventListener('activated', (event) => {
// `event.isUpdate` will be true if another version of the service
// worker was controlling the page when this version was registered.
if (!event.isUpdate) {
// service worker was updated and activated for the first time.
// If your service worker is configured to precache assets, those
// assets should all be available now.
// this will only happen if the browser was closed when a new version was made available
// and it will only happen once per service worker install.
// Reload to so all libs are correct version.
window.location.reload(true);
}
});
wb.register();
}
</script>