Skip to content

Commit

Permalink
Fix BGC+onSync essage broadcast
Browse files Browse the repository at this point in the history
  • Loading branch information
Spomky committed Mar 7, 2024
1 parent e88fb35 commit ad5cc0e
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 19 deletions.
7 changes: 7 additions & 0 deletions assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"sync-broadcast": {
"main": "src/sync-broadcast_controller.js",
"name": "pwa/sync-broadcast",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
}
},
"importmap": {
Expand Down
8 changes: 3 additions & 5 deletions assets/src/backgroundsync-form_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default class extends Controller {
redirection: { type: String, default: null },
};

async send(event) {
send = async (event) => {
event.preventDefault();
const form = this.element;
if (!form instanceof HTMLFormElement || !form.checkValidity()) {
Expand Down Expand Up @@ -45,15 +45,13 @@ export default class extends Controller {
window.location.assign(response.url);
return;
}
if (redirectTo) {
if (redirectTo !== undefined) {
window.location.assign(redirectTo);
}
} catch (error) {
if (redirectTo) {
if (redirectTo !== undefined) {
window.location.assign(redirectTo);
}
} finally {
form.reset();
}
}
}
6 changes: 3 additions & 3 deletions assets/src/connection-status_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default class extends Controller {
offlineMessage: { type: String, default: 'You are offline.' },
};

connect() {
connect = () => {
this.dispatchEvent('connect', {});
if (navigator.onLine) {
this.statusChanged({
Expand All @@ -37,11 +37,11 @@ export default class extends Controller {
});
});
}
dispatchEvent(name, payload) {
dispatchEvent = (name, payload) => {
this.dispatch(name, { detail: payload, prefix: 'connection-status' });
}

statusChanged(data) {
statusChanged = (data) => {
this.messageTargets.forEach((element) => {
element.innerHTML = data.message;
});
Expand Down
39 changes: 39 additions & 0 deletions assets/src/sync-broadcast_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

import { Controller } from '@hotwired/stimulus';

/* stimulusFetch: 'lazy' */
export default class extends Controller {
static values = {
channel: { type: String },
};
static targets = ['remaining'];

bc = null;

connect = () => {
if (!this.channelValue) {
throw new Error('The channel value is required.');
}
this.bc = new BroadcastChannel(this.channelValue);
this.bc.onmessage = this.messageReceived;
}

disconnect = () => {
if (this.bc !== null) {
this.bc.close();
}
}

dispatchEvent = (name, payload) => {
this.dispatch(name, { detail: payload, prefix: 'connection-status' });
}

messageReceived = async (event) => {
const data = event.data;
this.remainingTargets.forEach((element) => {
element.innerHTML = data.remaining;
});
this.dispatchEvent('status-changed', { detail: data });
}
}
5 changes: 4 additions & 1 deletion src/Dto/BackgroundSync.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ final class BackgroundSync
#[SerializedName('max_retention_time')]
public int $maxRetentionTime;

#[SerializedName('force_sync_callback')]
#[SerializedName('force_sync_fallback')]
public bool $forceSyncFallback;

#[SerializedName('broadcast_channel')]
public null|string $broadcastChannel = null;
}
13 changes: 10 additions & 3 deletions src/Resources/config/definition/service_worker.php
Original file line number Diff line number Diff line change
Expand Up @@ -342,13 +342,20 @@
->info('The HTTP method.')
->example(['POST', 'PUT', 'PATCH', 'DELETE'])
->end()
->scalarNode('broadcast_channel')
->defaultNull()
->info('The broadcast channel. Set null to disable.')
->example(['channel-1', 'background-sync-events'])
->end()
->integerNode('max_retention_time')
->defaultValue(60 * 24 * 5)
->defaultValue(60 * 24)
->info('The maximum retention time in minutes.')
->end()
->booleanNode('force_sync_callback')
->booleanNode('force_sync_fallback')
->defaultFalse()
->info('Whether to force the sync callback.')
->info(
'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.'
)
->end()
->end()
->end()
Expand Down
30 changes: 23 additions & 7 deletions src/Service/ServiceWorkerCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -332,16 +332,32 @@ private function processBackgroundSyncRule(Workbox $workbox, string $body): stri

$declaration = '';
foreach ($workbox->backgroundSync as $sync) {
$options = [
'maxRetentionTime' => $sync->maxRetentionTime,
'forceSyncCallback' => $sync->forceSyncFallback,
];
$options = array_filter($options, static fn (mixed $v): bool => $v !== null);
$options = count($options) === 0 ? '' : $this->serializer->serialize($options, 'json', $this->jsonOptions);
$forceSyncFallback = $sync->forceSyncFallback === true ? 'true' : 'false';
$broadcastChannel = '';
if ($sync->broadcastChannel !== null) {
$broadcastChannel = <<<BROADCAST_CHANNEL
,
"onSync": async ({queue}) => {
try {
await queue.replayRequests();
} catch (error) {
// Failed to replay one or more requests
} finally {
remainingRequests = await queue.getAll();
const bc = new BroadcastChannel('{$sync->broadcastChannel}');
bc.postMessage({name: '{$sync->queueName}', remaining: remainingRequests.length});
bc.close();
}
}
BROADCAST_CHANNEL;
}
$declaration .= <<<BACKGROUND_SYNC_RULE_STRATEGY
workbox.routing.registerRoute(
new RegExp('{$sync->regex}'),
new workbox.strategies.NetworkOnly({plugins: [new workbox.backgroundSync.BackgroundSyncPlugin('{$sync->queueName}',{$options})] }),
new workbox.strategies.NetworkOnly({plugins: [new workbox.backgroundSync.BackgroundSyncPlugin('{$sync->queueName}',{
"maxRetentionTime": {$sync->maxRetentionTime},
"forceSyncFallback": {$forceSyncFallback}{$broadcastChannel}
})] }),
'{$sync->method}'
);
BACKGROUND_SYNC_RULE_STRATEGY;
Expand Down

0 comments on commit ad5cc0e

Please sign in to comment.