Releases: GoogleChrome/workbox
Workbox v6.0.2
Workbox v6.0.2 resolves an issue that could prevent workbox-precaching
from working as expected when loaded via workbox-sw
.
(There was no v6.0.1 release.)
🐛 What's Fixed?
- Preserve symbols across builds and don't mangle
_handle
. [#2687]
Thanks!
Special thanks to @pidtuner for raising the issue that was resolved in this release.
Workbox v6.0.0
Overview of Workbox v6
We're happy to announce the release of Workbox v6!
🎉 What's New?
webpack improvements
This release includes additional bug fixes for better compatibility with webpack
. As of this release, workbox-webpack-plugin
requires webpack
v4.40.0 or later (for those still on the v4.x branch) or webpack
v.5.9.0 or later (for those who have updated to webpack
v5.x).
workbox-webpack-plugin
will also now take advantage of the immutable
metadata that webpack
automatically adds to hashed assets. In most cases, this means that explicitly using dontCacheBustURLMatching
in your workbox-webpack-plugin
configuration is no longer necessary.
workbox-strategies improvements
The best way to ensure third-party developers have the power to extend Workbox in ways that fully meet their needs is to base our own strategies on top of the extensibility mechanisms we expose to third-party developers.
Specifically, v6 introduces a new way for third-party developers to define their own Workbox strategies, and all of our built-in strategies have been rewritten on top of this mechanism.
This change also allowed us to rewrite the workbox-precaching
codebase to use workbox-strategies
as a base. This should not result in any breaking changes, and should lead to better long-term consistency in how the two modules access the network and cache.
See #2446, #2459 and #2569 for more details.
New strategy base class
In v6, all Workbox strategy classes (both built-in strategies as well as custom, third-party strategies) must extend the new Strategy
base class.
The Strategy
base class is responsible for two primary things:
- Invoking plugin lifecycle callbacks common to all strategy handlers (e.g. when they start, respond, and end).
- Creating a "handler" instance, that can manage state for each individual request a strategy is handling.
A new "handler" class
We previously had internal modules call fetchWrapper
and cacheWrapper
, which (as their name implies) wrap the various fetch and cache APIs with hooks into their lifecycle. This is the mechanism that currently allows plugins to work, but it's not exposed to developers.
The new "handler" class (which this proposal calls StrategyHandler
) will expose these methods so custom strategies can call fetch()
or cacheMatch()
and have any plugins that were added to the strategy instance automatically invoked.
This class would also make it possible for developers to add their own custom, lifecycle callbacks that might be specific to their strategies, and they would "just work" with the existing plugin interface.
New plugin lifecycle state
In Workbox v5, plugins are stateless. That means if a request for /index.html
triggers both the requestWillFetch
and cachedResponseWillBeUsed
callbacks, those two callbacks have no way of communicating with each other or even knowing that they were triggered by the same request.
In this proposal, all plugin callbacks will also be passed a new state
object. This state object will be unique to this particular plugin object and this particular strategy invocation (i.e. the call to handle()
).
This allows developers to write plugins where one callback can conditionally do something based on what another callback in the same plugin did (e.g. compute the time delta between running requestWillFetch
and fetchDidSucceed
or fetchDidFail
).
New plugin lifecycle callbacks
In order to fully leverage the plugin lifecycle state (mentioned above), you need to know when the lifecycle of a given strategy invocation starts and finishes.
To address this need (and others), the following new plugin lifecycle callbacks will be added:
- handlerWillStart: called before any handler logic starts running. This callback can be used to set the initial handler state (e.g. record the start time).
- handlerWillRespond: called before the strategies
handle()
method returns a response. This callback can be used to modify that response before returning it to a route handler or other custom logic. - handlerDidRespond: called after the strategy's
handle()
method returns a response. This callback can be used to record any final response details, e.g. after changes made by other plugins. - handlerDidComplete: called after all extend lifetime promises added to the event from the invocation of this strategy have settled. This callback can be used to report on any data that needs to wait until the handler is done in order to calculate (e.g. cache hit status, cache latency, network latency).
- handlerDidError: called if the handler was unable to provide a valid response from any source. This callback can be used to provide "fallback" content as an alternative to a network error.
Developers implementing their own custom strategies do not have to worry about invoking these callbacks themselves; that's all handled by a new Strategy
base class.
More accurate TypeScript types for handlers
TypeScript definitions for various callback methods have been normalized. This should lead to a better experience for developers who use TypeScript and write their own code to implement or call handlers.
See #2548.
workbox-recipes
This release includes a new module, workbox-recipes
, that combines common routing and caching strategy configurations into ready-to-use code that can be dropped in to your service worker.
You can read more about what's included in the first batch of recipes, as well as how to use them, in #2664.
workbox-window improvements
New messageSkipWaiting() method
A new method, messageSkipWaiting()
, has been added to the workbox-window
module to simplify the process of telling the "waiting" service worker to activate.
This offers some improvements over alternatives:
-
It calls
postMessage()
with the de facto standard message body,{type: 'SKIP_WAITING'}
, that a service worker generated by Workbox checks for to triggerskipWaiting()
. -
It chooses the correct "waiting" service worker to post this message to, even if it's not the same service worker that
workbox-window
was registered with.
See #2394.
Removal of "external" events in favor of an isExternal property
Many developers were confused by the concept of "external" events in workbox-window
, and in practice, they did not end up being a net-positive.
All "external" events are now represented as "normal" events with an isExternal
property set to true
. This allows developers who care about the distinction to still detect it, and developers who don't need to know can ignore the property.
See #2031.
Cleaner "Offer a page reload for users" recipe
Taken together, these two changes make the "Offer a page reload for users" recipe cleaner:
<script type="module">
import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.0.0/workbox-window.prod.mjs';
if ('serviceWorker' in navigator) {
const wb = new Workbox('/sw.js');
const showSkipWaitingPrompt = () => {
// This assumes a hypothetical createUIPrompt() method with
// onAccept and onReject callbacks:
const prompt = createUIPrompt({
onAccept: () => {
wb.addEventListener('controlling', () => {
window.location.reload();
});
// This will postMessage() to the waiting service worker.
wb.messageSkipWaiting();
},
onReject: () => {
prompt.dismiss();
}
});
};
// Listening for externalwaiting is no longer needed.
wb.addEventListener('waiting', showSkipWaitingPrompt);
wb.register();
}
</script>
sameOrigin parameter in matchCallback functions
A new boolean parameter, sameOrigin
, is passed to the matchCallback
function used in workbox-routing.
It's set to true
if the request is for a same-origin URL, and false
otherwise.
This simplifies some common boilerplate:
// In v5:
registerRoute(
({url}) => url.origin === self.location.origin &&
url.pathname.endsWith('.png'),
new StaleWhileRevalidate({cacheName: 'local-png'}),
);
// In v6:
registerRoute(
({sameOrigin, url}) => sameOrigin &&
url.pathname.endsWith('.png'),
new StaleWhileRevalidate({cacheName: 'local-png'}),
);
See #2487.
matchOptions are supported in workbox-expiration
You can now set matchOptions
in workbox-expiration
, which will then be passed through as the CacheQueryOptions
to the underlying cache.delete()
call. (Most developers won't need to do this.)
See #2206.
Precaching now processes entries one by one, not in bulk
workbox-precaching
has been updated so that only one entry in the precache manifest is requested and cached at a time, instead of attempting to request and cache all of them at once (leaving it to the browser to figure out how to throttle).
This should reduce the likelihood of net::ERR_INSUFFICIENT_RESOURCES
errors while precaching, and also should reduce the bandwidth contention between precaching and simultaneous requests made by the web app.
S...
Workbox v6.0.0-rc.0
Overview of Workbox v6
We're happy to announce the first release candidate of Workbox v6! We do not anticipate any more breaking changes in between now and the official v6 release.
In addition to the changes outlined in the previous release notes, the following has changed since Workbox v5.
🎉 What's New?
workbox-recipes
This release includes a new module, workbox-recipes
, that combines common routing and caching strategy configurations into ready-to-use code that can be dropped in to your service worker.
You can read more about what's included in the first batch of recipes, as well as how to use them, in #2664.
webpack v5 compatibility improvements
This release includes additional bug fixes for better compatibility with webpack
. As of this release, workbox-webpack-plugin
requires webpack
v4.40.0 or later (for those still on the v4.x branch) or webpack
v.5.4.0 or later (for those who have updated to webpack
v5.x).
workbox-webpack-plugin
will also now take advantage of the immutable
metadata that webpack
automatically adds to hashed assets. In most cases, this means that explicitly using dontCacheBustURLMatching
in your workbox-webpack-plugin
configuration is no longer necessary.
Thanks!
Thank you to @dermoumi for their contributions to this release.
Installation of the latest pre-release version
We are using the next
tag in npm
for the current pre-release version. To install a given module use, e.g., npm install --save-dev workbox-webpack-plugin@next
.
Workbox v6.0.0-alpha.3
Overview of Workbox v6
We're happy to announce the third alpha release of Workbox v6! In addition to the changes outlined in the previous release notes, the following has changed since Workbox v5.
🎉 What's New?
Under-the-hood workbox-precaching improvements
This release includes a substantial rewrite to the implementation of workbox-precaching
, to build on top of other standard Workbox idioms (like Route
s, Strategy
subclasses, and custom plugins) as much as possible. There are a few breaking changes, described in the follow section, but they are mostly limited to uncommon use cases, when PrecacheController
is instantiated directly. For the most part, these changes are meant to be invisible to developers, but should lead to be better consistency in how routing and request handling works across all of Workbox.
You can read more about what's change in #2638
webpack v5 compatibility
As of this release, workbox-webpack-plugin
should be compatible with webpack
v5.0.0. We have also raised the minimum required version of webpack
to v4.4.0, which should be a straightforward upgrade for developers who need to remain on webpack
v4.x.
While all of the public interfaces remain the same, signfifcant changes were made to the code used to determine which webpack
assets make it into your precache manifest. These take advantage of new methods that were added in webpack
v4.4.0, and which have to be used in webpack
v5.0.0. We encourage developers to test workbox-webpack-plugin
carefully, and raise issues if you find discrepencies like URLs missing from your precache manifest! This applies whether you are remaining on webpack
v4.4.0, or are upgrade to webpack
v5.0.0.
Note: At this time, workbox-webpack-plugin
has issues detecting the correct URLs for HTML assets created by html-webpack-plugin
in webpack
v5.0.0. You can follow jantimon/html-webpack-plugin#1522 for updates.
cacheKeyWillBeUsed can be used to cache non-GET requests
Only GET
requests can be used as cache keys, but there are scenarios in which you might want to use a combination of plugins to transform a POST
or PUT
request into a cacheable GET
request.
You can now use the cacheKeyWillBeUsed
lifecycle callback in a plugin to return a GET
request with whatever URL you'd like to use as a cache key, and that can then allow the response associated with a POST
or PUT
to be cached.
See #2615 for more details. Thanks to @markbrocato for their contribution.
⚠️ Breaking Changes
workbox-precaching
Note: The following changes primarily apply to direct usage of the PrecacheController
class. Most developers don't use PrecacheController
directly, and instead use static helper methods like precacheAndRoute()
exported by workbox-precaching
. [#2639]
-
The
PrecacheController
constructor now takes in an object with specific properties as its parameter, instead of a string. This object supports the following properties:cacheName
(serving the same purpose as the string that was passed in to the constructor in v5),plugins
(replacing theaddPlugins()
method from v5), andfallbackToNetwork
(replacing the similar option that was passed tocreateHandler()
and `createHandlerBoundToURL() in v5). -
The
install()
andactivate()
methods ofPrecacheController
now take exactly one parameter, which should be set to a correspondingInstallEvent
orActivateEvent
, respectively. -
The
addRoute()
method has been removed fromPrecacheController
. In its place, the newPrecacheRoute
class can be used to create a route that you can then register. -
The
precacheAndRoute()
method has been removed fromPrecacheController
. (It still exists as a static helper method exported by theworkbox-precaching
module.) It was removed becausePrecacheRoute
can be used instead. -
The
createMatchCalback()
method has been removed fromPrecacheController
. The newPrecacheRoute
can be used instead. -
The
createHandler()
method has been removed fromPrecacheController
. Thestrategy
property of thePrecacheController
object can be used to handle requests instead. -
The
createHandler()
static export has already been removed from theworkbox-precaching
module. In its place, developers should construct aPrecacheController
instance and use itsstrategy
property. -
The route registered with
precacheAndRoute()
is now a "real" route that usesworkbox-routing
'sRouter
class under the hood. This may lead to a different evaluation order of your routes if you interleave calls toregisterRoute()
andprecacheAndRoute()
. See #1857 and #2402 for more details.
workbox-webpack-plugin
- The minimum required version of webpack has been increased to
v4.4.0
. (See previous section for otherwebpack
updates.) [#2641]
Installation of the latest pre-release version
We are using the next
tag in npm
for the current pre-release version. To install a given module use, e.g., npm install --save-dev workbox-webpack-plugin@next
.
Workbox v5.1.4
The v5.1.4 release contains a dependency update for rollup-plugin-terser
, resolving a security error with one of its dependencies.
See #2601
Workbox v6.0.0-alpha.2
Workbox v6.0.0-alpha.2
includes updates to various underlying npm
dependencies, but is otherwise identical to the previous v6.0.0-alpha.1
release.
Installation of the latest pre-release version
We are using the next
tag in npm
for the current pre-release version. To install a given module use, e.g., npm install --save-dev workbox-webpack-plugin@next
.
Workbox v6.0.0-alpha.1
Overview of Workbox v6
We're happy to announce the first alpha release of Workbox v6!
🎉 What's New?
workbox-strategies improvements
The best way to ensure third-party developers have the power to extend Workbox in ways that fully meet their needs is to base our own strategies on top of the extensibility mechanisms we expose to third-party developers.
Specifically, v6 introduces a new way for third-party developers to define their own Workbox strategies, and all of our built-in strategies have been rewritten on top of this mechanism.
This change also allowed us to rewrite the workbox-precaching
codebase to use workbox-strategies
as a base. This should not result in any breaking changes, and should lead to better long-term consistency in how the two modules access the network and cache.
See #2446, #2459 and #2569 for more details.
New strategy base class
In v6, all Workbox strategy classes (both built-in strategies as well as custom, third-party strategies) must extend the new Strategy
base class.
The Strategy
base class is responsible for two primary things:
- Invoking plugin lifecycle callbacks common to all strategy handlers (e.g. when they start, respond, and end).
- Creating a "handler" instance, that can manage state for each individual request a strategy is handling.
A new "handler" class
We previously had internal modules call fetchWrapper
and cacheWrapper
, which (as their name implies) wrap the various fetch and cache APIs with hooks into their lifecycle. This is the mechanism that currently allows plugins to work, but it's not exposed to developers.
The new "handler" class (which this proposal calls StrategyHandler
) will expose these methods so custom strategies can call fetch()
or cacheMatch()
and have any plugins that were added to the strategy instance automatically invoked.
This class would also make it possible for developers to add their own custom, lifecycle callbacks that might be specific to their strategies, and they would "just work" with the existing plugin interface.
New plugin lifecycle state
In Workbox v5, plugins are stateless. That means if a request for /index.html
triggers both the requestWillFetch
and cachedResponseWillBeUsed
callbacks, those two callbacks have no way of communicating with each other or even knowing that they were triggered by the same request.
In this proposal, all plugin callbacks will also be passed a new state
object. This state object will be unique to this particular plugin object and this particular strategy invocation (i.e. the call to handle()
).
This allows developers to write plugins where one callback can conditionally do something based on what another callback in the same plugin did (e.g. compute the time delta between running requestWillFetch
and fetchDidSucceed
or fetchDidFail
).
New plugin lifecycle callbacks
In order to fully leverage the plugin lifecycle state (mentioned above), you need to know when the lifecycle of a given strategy invocation starts and finishes.
To address this need (and others), the following new plugin lifecycle callbacks will be added:
- handlerWillStart: called before any handler logic starts running. This callback can be used to set the initial handler state (e.g. record the start time).
- handlerWillRespond: called before the strategies
handle()
method returns a response. This callback can be used to modify that response before returning it to a route handler or other custom logic. - handlerDidRespond: called after the strategy's
handle()
method returns a response. This callback can be used to record any final response details, e.g. after changes made by other plugins. - handlerDidComplete: called after all extend lifetime promises added to the event from the invocation of this strategy have settled. This callback can be used to report on any data that needs to wait until the handler is done in order to calculate (e.g. cache hit status, cache latency, network latency).
- handlerDidError: called if the handler was unable to provide a valid response from any source. This callback can be used to provide "fallback" content as an alternative to a network error.
Developers implementing their own custom strategies do not have to worry about invoking these callbacks themselves; that's all handled by a new Strategy
base class.
More accurate TypeScript types for handlers
TypeScript definitions for various callback methods have been normalized. This should lead to a better experience for developers who use TypeScript and write their own code to implement or call handlers.
See #2548.
workbox-window improvements
New messageSkipWaiting() method
A new method, messageSkipWaiting()
, has been added to the workbox-window
module to simplify the process of telling the "waiting" service worker to activate.
This offers some improvements over alternatives:
-
It calls
postMessage()
with the de facto standard message body,{type: 'SKIP_WAITING'}
, that a service worker generated by Workbox checks for to triggerskipWaiting()
. -
It chooses the correct "waiting" service worker to post this message to, even if it's not the same service worker that
workbox-window
was registered with.
See #2394.
Removal of "external" events in favor of an isExternal property
Many developers were confused by the concept of "external" events in workbox-window
, and in practice, they did not end up being a net-positive.
All "external" events are now represented as "normal" events with an isExternal
property set to true
. This allows developers who care about the distinction to still detect it, and developers who don't need to know can ignore the property.
See #2031.
Cleaner "Offer a page reload for users" recipe
Taken together, these two changes make the "Offer a page reload for users" recipe cleaner:
<script type="module">
import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.0.0-alpha.1/workbox-window.prod.mjs';
if ('serviceWorker' in navigator) {
const wb = new Workbox('/sw.js');
const showSkipWaitingPrompt = () => {
// This assumes a hypothetical createUIPrompt() method with
// onAccept and onReject callbacks:
const prompt = createUIPrompt({
onAccept: () => {
wb.addEventListener('controlling', () => {
window.location.reload();
});
// This will postMessage() to the waiting service worker.
wb.messageSkipWaiting();
},
onReject: () => {
prompt.dismiss();
}
});
};
// Listening for externalwaiting is no longer needed.
wb.addEventListener('waiting', showSkipWaitingPrompt);
wb.register();
}
</script>
sameOrigin parameter in matchCallback functions
A new boolean parameter, sameOrigin
, is passed to the matchCallback
function used in workbox-routing.
It's set to true
if the request is for a same-origin URL, and false
otherwise.
This simplifies some common boilerplate:
// In v5:
registerRoute(
({url}) => url.origin === self.location.origin &&
url.pathname.endsWith('.png'),
new StaleWhileRevalidate({cacheName: 'local-png'}),
);
// In v6:
registerRoute(
({sameOrigin, url}) => sameOrigin &&
url.pathname.endsWith('.png'),
new StaleWhileRevalidate({cacheName: 'local-png'}),
);
See #2487.
matchOptions are supported in workbox-expiration
You can now set matchOptions
in workbox-expiration
, which will then be passed through as the CacheQueryOptions
to the underlying cache.delete()
call. (Most developers won't need to do this.)
See #2206.
Precaching now processes entries one by one, not in bulk
workbox-precaching
has been updated so that only one entry in the precache manifest is requested and cached at a time, instead of attempting to request and cache all of them at once (leaving it to the browser to figure out how to throttle).
This should reduce the likelihood of net::ERR_INSUFFICIENT_RESOURCES
errors while precaching, and also should reduce the bandwidth contention between precaching and simultaneous requests made by the web app.
See #2528.
PrecacheFallbackPlugin allows for easier offline fallback
workbox-precaching
now includes a PrecacheFallbackPlugin
, which implements the new handlerDidError
lifecycle method added in v6.
This makes it easy to specify a precached URL as a "fallback" for a given strategy when a response otherwise wouldn't be available. The plugin will take care of properly constructing the correct cache key for the precached URL, including any revision parameter that's needed.
Here's a sample of using it to respond with a precached /offline.html
when the NetworkOnly
strategy can't generate a response for a navigation request—in other words, displaying a custom offline HTML page:
import {PrecacheFallbackPlugin, precacheAndRoute} from 'workbox-precaching';
import {registerRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';
// Ensure that /offline.html is part of your precache manifest!
precacheAndRoute(self.__WB_MANIFEST);
registerRoute(
({request}) => request.mode === 'navigate',
new NetworkOnly({
plugins: [
new PrecacheFallbackPlugin({
fa...
Workbox v5.1.3
🐛 What's Fixed?
workbox-build
- Correct
workbox-build
'sgetManifest()
JSDoc [#2429]
workbox-cli
- Don't check
swSrc
for hardcoded injection point inwizard
flow [#2451]
workbox-core
handlerCallback
JSDocs update [#2440]
workbox-precaching
Thanks!
Special thanks to @akonchady for contributing a PR that went in to this release.
Workbox v5.1.2
🐛 What's Fixed?
workbox-build
- Reverted the
strip-comments
dependency to an earlier revision, to provide continued compatibility with the v8.x.y releases ofnode
. [#2416]
Thanks!
Special thanks to @Mister-Hope for raising issues that were resolved in this release.
Workbox v5.1.1
(We ran into some issues with the v5.1.0
release process, so v5.1.1
is a republish of the same code.)
🎉 What's New?
workbox-routing
- Adjusted the debug logging code so that a URL's
hash
portion is displayed. [#2371]
workbox-webpack-plugin
- A new
compileSrc
option (defaulting totrue
) has been added. If set tofalse
, thenwebpack
will not run theswSrc
file through a compilation. This can be useful if you want yourswDest
output to be, e.g., a JSON file which contains your precache manifest. [#2412]
🐛 What's Fixed?
workbox-webpack-plugin
- Switch to official package exports when using internal
webpack
modules. [#2397] webpackCompilationPlugins
that customize theswSrc
compilation should now be properly applied. [#2400]
Thanks!
Special thanks to @aritsune, @bailnl, @novaknole and @pizzafox for raising issues that were resolved in this release.