Skip to content

From 1.5.x to 1.6.0

This page describes the changes you need to make when upgrading from version 1.5.x to 1.6.0.

Success

Nothing is removed in 1.6.0. Everything below keeps working exactly as before. The release exists to give you a full minor version to migrate before 2.0.0 takes the deprecated pieces away.

The bundle is narrowing its scope

The bundle is going back to what it does well: the web manifest, the service worker, and the favicons, icons and screenshots. Everything on the client-integration side is leaving.

Two things drove the decision. Wrapping a browser API in a generic, configurable Stimulus controller turns out to be a lot of abstraction for very little reuse: every project wants its own behaviour, its own UI and its own error handling. And several of those controllers push real-time, client-side interactions through the server and back, a round trip that is rarely what an application actually wants.

The full rationale is in this comment.

Deprecated: the Stimulus controllers

All 27 controllers shipped by the bundle are deprecated and will be removed in 2.0.0, along with the @spomky-labs/pwa-bundle npm package.

Each one prints a warning in the browser console the first time it is mounted:

[pwa-bundle] The "pwa--web-push" Stimulus controller is deprecated since 1.6.0 and will be
removed in 2.0.0. Copy the controller into your own application and register it there.

What to do: copy the controllers you actually use into your own application and register them there. They are plain Stimulus controllers with no dependency on the bundle, so nothing is lost in the move, and you get to drop the parts you never needed.

# for instance
cp vendor/spomky-labs/pwa-bundle/assets/src/geolocation_controller.js assets/controllers/

The two page-side helpers exported through @spomky-labs/pwa/helpers, onPeriodicSync() and registerPeriodicSync(), are deprecated too. registerPeriodicSync() is a handful of lines you can inline:

assets/app.js
const registration = await navigator.serviceWorker.ready;
const status = await navigator.permissions.query({ name: 'periodic-background-sync' });

if (status.state === 'granted' && 'periodicSync' in registration) {
    const tags = await registration.periodicSync.getTags();
    if (!tags.includes('my-tag')) {
        await registration.periodicSync.register('my-tag', { minInterval: 24 * 60 * 60 * 1000 });
    }
}

Deprecated: part of the service worker helpers

The service worker generated by the bundle used to declare a number of helper functions. Most of them wrap events the bundle itself never handles: push, notificationclick, message, periodicsync and the three backgroundfetch events have no producer on the PHP side.

Service worker listeners are additive, and your own source file (the src option) is appended last, so a plain self.addEventListener() there does exactly the same job without the indirection.

The following helpers are deprecated:

Helper Replacement
registerCacheFirst() Build the strategy and call workbox.routing.registerRoute() directly
registerMessageTask() self.addEventListener('message', ...)
registerPushTask() self.addEventListener('push', ...)
registerNotificationAction() self.addEventListener('notificationclick', ...)
registerPeriodicSyncTask() self.addEventListener('periodicsync', ...)
registerBackgroundFetchTask() self.addEventListener('backgroundfetchsuccess', ...) and its siblings
openBackgroundFetchDatabase() Open your own database
structuredPushNotificationSupport() Parse the payload and call showNotification() yourself
simplePushNotificationSupport() Same
notifyPeriodicSyncClients() Create your own BroadcastChannel and post to it

Each of them warns in the console when it is actually called, so an application that already stopped using them gets a silent service worker.

What stays

These are not going anywhere, because your own source file cannot replace them: they either arbitrate an order between the rules the bundle generates, or carry a state shared with them.

  • registerInstallTask() and precacheResources()
  • registerCacheName(), openCache() and the new registerClearCacheListener()
  • statusGuard(), createBackgroundSyncPlugin() and createBackgroundSyncPluginWithBroadcast()
  • the SKIP_WAITING message handler, which is the service worker half of the update flow

Migrating

Replace the calls in your own service worker source:

assets/sw.js
// registerPushTask(structuredPushNotificationSupport);
self.addEventListener('push', (event) => {
    const { title, options } = JSON.parse(event.data.text());
    event.waitUntil(self.registration.showNotification(title, options));
});

// registerNotificationAction('*', handler);
self.addEventListener('notificationclick', (event) => {
    event.notification.close();
    event.waitUntil(handler(event));
});

// registerPeriodicSyncTask('my-tag', callback);
self.addEventListener('periodicsync', (event) => {
    if (event.tag === 'my-tag') {
        event.waitUntil(callback(event));
    }
});

// registerMessageTask(callback);
self.addEventListener('message', (event) => {
    event.waitUntil(callback(event));
});

Then turn the helpers off:

config/packages/pwa.yaml
pwa:
    serviceworker:
        workbox:
            keep_deprecated_helpers: false

As long as this option is left to true, the bundle triggers a deprecation notice at container build time. Setting it to false is what silences it, and it is the exact change 2.0.0 will make for you.

Warning

Setting keep_deprecated_helpers to false stops the idb library from being imported into the service worker and copied to the public folder, because openBackgroundFetchDatabase() was its only consumer. If your own source file uses self.idb, switch to indexedDB.open() or import the library yourself.

Deprecated: background fetch

The background_fetch option is deprecated and will be removed in 2.0.0.

It decides for you that a click opens a given URL, that downloads are chunked into a fixed IndexedDB schema and that the notification title is rewritten with {title} ✅. That is a lot of opinion for a feature every application ends up wanting differently.

config/packages/pwa.yaml
pwa:
    serviceworker:
        workbox:
            background_fetch:      # deprecated since 1.6.0
                enabled: true

Handle the events in your own source file instead. self.idb remains available as long as keep_deprecated_helpers is true, and the storage is a dozen lines with plain indexedDB:

assets/sw.js
self.addEventListener('backgroundfetchsuccess', (event) => {
    event.waitUntil((async () => {
        const records = await event.registration.matchAll();
        for (const record of records) {
            const response = await record.responseReady;
            // store it the way your application needs
        }
        await event.updateUI({ title: 'Download complete' });
    })());
});

Danger

Enabling background_fetch while keep_deprecated_helpers is false now fails at container build time with an explicit message, rather than producing a service worker that throws a ReferenceError in the browser.

New: purging your own caches

clear_cache only ever deleted the caches the bundle registers itself through registerCacheName(). A cache your own service worker source opens with caches.open() survived every install, silently.

The new registerClearCacheListener() closes the gap. The callback receives every cache name currently stored and returns the ones to delete:

assets/sw.js
registerClearCacheListener((names) =>
    names.filter((name) => name.startsWith('my-app-') && name !== 'my-app-v3')
);

A callback rather than a list of names in the configuration, because the interesting cases are dynamic: versioned caches where the current one must survive, prefixes, anything computed at runtime.

Callbacks may be async, and one throwing is logged without stopping the others.

See Cache Cleaning.

Deprecated: favicons.use_start_image

The iOS startup images used to be a favicon setting, which they only ever were because they shared a source image. They now have a section of their own:

config/packages/pwa.yaml
pwa:
    favicons:
        enabled: true
        use_start_image: false   # deprecated since 1.6.0

    startup_images:
        enabled: false           # this instead

Nothing else has to move. use_start_image still seeds startup_images.enabled, and the images keep borrowing their source, background color, border radius and SVG attributes from the favicon of the same color scheme. An existing configuration produces the very same files, content hashes included.

New: startup images described by a Twig template

A startup image could only ever be the favicon source, scaled down and centered over a background color. It can now be any document you care to write:

config/packages/pwa.yaml
pwa:
    startup_images:
        template: 'pwa/startup_image.html.twig'
        context:
            subtitle: 'Identify every plant, even offline.'

The template is rendered by your own Twig environment and painted by a headless Chrome driven by Panther — a compile-time dependency, and only when a template is configured. Without one, nothing new is required.

See Startup Images.

New: localized manifest members

The manifest can now carry every translation in a single file, through the *_localized members of the specification, instead of one compiled file per locale:

config/packages/pwa.yaml
pwa:
    manifest:
        localization_strategy: 'inline'   # or 'both', or 'files'

files is the default and the historical behaviour, so nothing changes unless you ask for it.

See Translations.

Deprecated: choosing the Workbox version

The bundle carried two copies of the Workbox libraries, 7.0.0 and 7.3.0. Both are replaced by a single 7.4.1 copy, and choosing anything else is deprecated:

config/packages/pwa.yaml
pwa:
    serviceworker:
        workbox:
            config:
                use_cdn: true       # deprecated since 1.6.0
                version: '7.3.0'    # deprecated since 1.6.0

Everything the bundle generates — the imports, the caching strategies, the plugins, the helpers — is written against the API of the version it ships. Pinning another one produced a service worker written for one version and running against another, failing in the browser rather than at compile time.

What to do: remove both options and let the bundled files be served from your own public folder. Then clear the stale copies, which pwa:compile writes past but never removes:

terminal
rm -rf public/workbox-v7.0.0 public/workbox-v7.3.0
php bin/console pwa:compile

Info

The flat workbox.use_cdn and workbox.version, deprecated since 1.5.0, no longer point at their workbox.config.* counterparts: those are deprecated too. An application still on the flat spelling is told twice — once for the option it wrote, once for the section the value is migrated into. Removing the option silences both.

workbox_public_url and debug are not deprecated: where your server exposes the files, and whether Workbox logs, remain yours to decide.

See Workbox Files.

Changed: the two image processors agree on their output

GD and Imagick used to leave the encoding quality to their extension, so the very same configuration produced noticeably different files: GD fell back on its default of 75, Imagick picked 92, or the quality of the source when that source was a JPEG. Both now state 85 explicitly, and both spell jpg and jpeg the same way.

What to do: nothing, beyond expecting your lossy images (screenshots, and any icon compiled to JPEG, WebP or AVIF) to be regenerated with a slightly different weight on the next pwa:compile. PNG output is unaffected.

Changed: a missing image processor extension is reported earlier

Pointing pwa.image_processor at a built-in processor whose PHP extension is not loaded used to fail much later, inside the container compilation, with a bare "You have requested a non-existent service pwa.image_processor.imagick". It now fails at configuration time, naming the missing extension.

Changed: Dto\PageCache is an alias

SpomkyLabs\PwaBundle\Dto\PageCache, deprecated since 1.2.0 in favour of ResourceCache, was a subclass of a class documented as final. Symfony's DebugClassLoader told every application running in dev or test off for an inheritance the bundle owned and they had no way to remove.

The name is now a class alias. It still resolves, still passes any instanceof ResourceCache check, and triggers a deprecation of its own instead of a spurious one. Nothing to change beyond migrating to ResourceCache, as 1.2.0 already asked.

Migration checklist

  • [ ] Copy the Stimulus controllers you use into your own application, register them there
  • [ ] Drop the @spomky-labs/pwa-bundle npm dependency once nothing imports it
  • [ ] Replace onPeriodicSync() and registerPeriodicSync() with the native calls
  • [ ] Replace the deprecated service worker helpers with self.addEventListener() in your src
  • [ ] Check the browser console: any remaining [pwa-bundle] warning points at a call you missed
  • [ ] Set keep_deprecated_helpers: false
  • [ ] If you used self.idb in your own source, switch to indexedDB.open()
  • [ ] Replace background_fetch with your own backgroundfetchsuccess handler
  • [ ] Declare the caches you open yourself with registerClearCacheListener()
  • [ ] Move favicons.use_start_image to startup_images.enabled
  • [ ] Remove use_cdn and version from the Workbox configuration, both spellings, and delete the stale workbox-v7.* folders from public/
  • [ ] Replace any remaining Dto\PageCache reference with Dto\ResourceCache
  • [ ] Run php bin/console pwa:compile and test with APP_ENV=dev to surface the deprecations

Still deprecated (from earlier versions)

The following options were deprecated in earlier versions and will also be removed in 2.0.0:

Option Replacement Since
pwa.serviceworker.workbox.use_cdn None — remove it, see above 1.5.0
pwa.serviceworker.workbox.version None — remove it, see above 1.5.0
pwa.serviceworker.workbox.workbox_public_url pwa.serviceworker.workbox.config.workbox_public_url 1.5.0
pwa.favicons.src pwa.favicons.default.src 1.3.0
pwa.favicons.src_dark pwa.favicons.dark.src 1.3.0
pwa.favicons.background_color pwa.favicons.default.background_color 1.3.0
pwa.favicons.background_color_dark pwa.favicons.dark.background_color 1.3.0
pwa.favicons.border_radius pwa.favicons.default.border_radius 1.3.0
pwa.favicons.image_scale pwa.favicons.default.image_scale 1.3.0
pwa.path_type_reference URL node path_type_reference parameter 1.1.0