diff --git a/packages/workbox-background-sync/src/Queue.ts b/packages/workbox-background-sync/src/Queue.ts index 97dd895f1..4e0518396 100644 --- a/packages/workbox-background-sync/src/Queue.ts +++ b/packages/workbox-background-sync/src/Queue.ts @@ -27,8 +27,9 @@ interface OnSyncCallback { } export interface QueueOptions { - onSync?: OnSyncCallback; + forceSyncFallback?: boolean; maxRetentionTime?: number; + onSync?: OnSyncCallback; } interface QueueEntry { @@ -79,6 +80,7 @@ class Queue { private readonly _onSync: OnSyncCallback; private readonly _maxRetentionTime: number; private readonly _queueStore: QueueStore; + private readonly _forceSyncFallback: boolean; private _syncInProgress = false; private _requestsAddedDuringSync = false; @@ -100,8 +102,17 @@ class Queue { * @param {number} [options.maxRetentionTime=7 days] The amount of time (in * minutes) a request may be retried. After this amount of time has * passed, the request will be deleted from the queue. + * @param {boolean} [options.forceSyncFallback=false] If `true`, instead + * of attempting to use background sync events, always attempt to replay + * queued request at service worker startup. Most folks will not need + * this, unless you explicitly target a runtime like Electron that + * exposes the interfaces for background sync, but does not have a working + * implementation. */ - constructor(name: string, {onSync, maxRetentionTime}: QueueOptions = {}) { + constructor( + name: string, + {forceSyncFallback, onSync, maxRetentionTime}: QueueOptions = {}, + ) { // Ensure the store name is not already being used if (queueNames.has(name)) { throw new WorkboxError('duplicate-queue-name', {name}); @@ -112,6 +123,7 @@ class Queue { this._name = name; this._onSync = onSync || this.replayRequests; this._maxRetentionTime = maxRetentionTime || MAX_RETENTION_TIME; + this._forceSyncFallback = Boolean(forceSyncFallback); this._queueStore = new QueueStore(this._name); this._addSyncListener(); @@ -379,7 +391,8 @@ class Queue { * Registers a sync event with a tag unique to this instance. */ async registerSync(): Promise { - if ('sync' in self.registration) { + // See https://github.com/GoogleChrome/workbox/issues/2393 + if ('sync' in self.registration && !this._forceSyncFallback) { try { await self.registration.sync.register(`${TAG_PREFIX}:${this._name}`); } catch (err) { @@ -397,13 +410,14 @@ class Queue { /** * In sync-supporting browsers, this adds a listener for the sync event. - * In non-sync-supporting browsers, this will retry the queue on service - * worker startup. + * In non-sync-supporting browsers, or if _forceSyncFallback is true, this + * will retry the queue on service worker startup. * * @private */ private _addSyncListener() { - if ('sync' in self.registration) { + // See https://github.com/GoogleChrome/workbox/issues/2393 + if ('sync' in self.registration && !this._forceSyncFallback) { self.addEventListener('sync', (event: SyncEvent) => { if (event.tag === `${TAG_PREFIX}:${this._name}`) { if (process.env.NODE_ENV !== 'production') { @@ -450,8 +464,9 @@ class Queue { if (process.env.NODE_ENV !== 'production') { logger.log(`Background sync replaying without background sync event`); } - // If the browser doesn't support background sync, retry - // every time the service worker starts up as a fallback. + // If the browser doesn't support background sync, or the developer has + // opted-in to not using it, retry every time the service worker starts up + // as a fallback. void this._onSync({queue: this}); } } diff --git a/test/workbox-background-sync/sw/test-Queue.mjs b/test/workbox-background-sync/sw/test-Queue.mjs index efa46d066..08ac4ce35 100644 --- a/test/workbox-background-sync/sw/test-Queue.mjs +++ b/test/workbox-background-sync/sw/test-Queue.mjs @@ -205,6 +205,13 @@ describe(`Queue`, function () { expect(onSync.calledOnce).to.be.true; } }); + + it(`should run 'onSync' on instantiation when forceSyncFallback is set`, async function () { + const onSync = sandbox.spy(); + new Queue('foo', {onSync, forceSyncFallback: true}); + + expect(onSync.calledOnce).to.be.true; + }); }); describe(`pushRequest`, function () {