workbox-expiration

It's fairly common to want to put restrictions on a cache in terms of how long it should allow items to be stored in a cache or how many items should be kept in a cache. Workbox provides this functionality through the workbox-expiration plugin that allows you to limit the number of entries in a cache and / or remove entries that have been cached for a long period of time.

Restrict the Number of Cache Entries

To restrict the number of entries stored in a cache, you can use the maxEntries option like so:

import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
import {ExpirationPlugin} from 'workbox-expiration';

registerRoute(
  ({request}) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'image-cache',
    plugins: [
      new ExpirationPlugin({
        maxEntries: 20,
      }),
    ],
  })
);

With this, the Plugin will be added to this route. After a cached response is used or a new request is added to the cache, the plugin will look at the configured cache and ensure that the number of cached entries doesn't exceed the limit. If it does, the oldest entries will be removed.

Restrict the Age of Cached Entries

To restrict how long a request is cached for, you can define a max age in seconds using the maxAgeSeconds option like so:

import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
import {ExpirationPlugin} from 'workbox-expiration';

registerRoute(
  ({request}) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'image-cache',
    plugins: [
      new ExpirationPlugin({
        maxAgeSeconds: 24 * 60 * 60,
      }),
    ],
  })
);

The plugin will check and remove entries after each request or cache update.

Advanced Usage

If you'd like to use the expiration logic separate from any other Workbox module, you can do so with the CacheExpiration class.

To apply restrictions to a cache, you'd create an instance of CacheExpiration for the cache you want to control like so:

import {CacheExpiration} from 'workbox-expiration';

const cacheName = 'my-cache';
const expirationManager = new CacheExpiration(cacheName, {
  maxAgeSeconds: 24 * 60 * 60,
  maxEntries: 20,
});

Whenever you update a cached entry, you need to call the updateTimestamp() method so that its age is updated.

await openCache.put(request, response);

await expirationManager.updateTimestamp(request.url);

Then, whenever you want to expire a set of entries, you can call the expireEntries() method which will enforce the maxAgeSeconds and maxEntries configuration.

await expirationManager.expireEntries();

Types

CacheExpiration

The CacheExpiration class allows you define an expiration and / or limit on the number of responses stored in a Cache.

Properties

  • constructor

    void

    To construct a new CacheExpiration instance you must provide at least one of the config properties.

    The constructor function looks like:

    (cacheName: string,config?: CacheExpirationConfig)=> {...}

    • cacheName

      string

      Name of the cache to apply restrictions to.

    • config

      CacheExpirationConfig optional

  • delete

    void

    Removes the IndexedDB object store used to keep track of cache expiration metadata.

    The delete function looks like:

    ()=> {...}

    • returns

      Promise<void>

  • expireEntries

    void

    Expires entries for the given cache and given criteria.

    The expireEntries function looks like:

    ()=> {...}

    • returns

      Promise<void>

  • isURLExpired

    void

    Can be used to check if a URL has expired or not before it's used.

    This requires a look up from IndexedDB, so can be slow.

    Note: This method will not remove the cached entry, call expireEntries() to remove indexedDB and Cache entries.

    The isURLExpired function looks like:

    (url: string)=> {...}

    • url

      string

    • returns

      Promise<boolean>

  • updateTimestamp

    void

    Update the timestamp for the given URL. This ensures the when removing entries based on maximum entries, most recently used is accurate or when expiring, the timestamp is up-to-date.

    The updateTimestamp function looks like:

    (url: string)=> {...}

    • url

      string

    • returns

      Promise<void>

ExpirationPlugin

This plugin can be used in a workbox-strategy to regularly enforce a limit on the age and / or the number of cached requests.

It can only be used with workbox-strategy instances that have a custom cacheName property set. In other words, it can't be used to expire entries in strategy that uses the default runtime cache name.

Whenever a cached response is used or updated, this plugin will look at the associated cache and remove any old or extra responses.

When using maxAgeSeconds, responses may be used once after expiring because the expiration clean up will not have occurred until after the cached response has been used. If the response has a "Date" header, then a light weight expiration check is performed and the response will not be used immediately.

When using maxEntries, the entry least-recently requested will be removed from the cache first.

Properties

  • constructor

    void

    The constructor function looks like:

    (config?: ExpirationPluginOptions)=> {...}

  • deleteCacheAndMetadata

    void

    This is a helper method that performs two operations:

    • Deletes all the underlying Cache instances associated with this plugin instance, by calling caches.delete() on your behalf.
    • Deletes the metadata from IndexedDB used to keep track of expiration details for each Cache instance.

    When using cache expiration, calling this method is preferable to calling caches.delete() directly, since this will ensure that the IndexedDB metadata is also cleanly removed and open IndexedDB instances are deleted.

    Note that if you're not using cache expiration for a given cache, calling caches.delete() and passing in the cache's name should be sufficient. There is no Workbox-specific method needed for cleanup in that case.

    The deleteCacheAndMetadata function looks like:

    ()=> {...}

    • returns

      Promise<void>

ExpirationPluginOptions

Properties

  • matchOptions

    CacheQueryOptions optional

  • maxAgeSeconds

    number optional

  • maxEntries

    number optional

  • purgeOnQuotaError

    boolean optional