GoogleChrome / GoogleChrome/workbox

Consider adding `maxUnusedSeconds` and `updateStale` to `ExpirationPlugin` config

Open
#3,316 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
JavaScript
Stars
13k
Forks
880
Avg merge
2h 44m
Merged PRs (30d)
8

Description

Hello new team :)

You closed #2863 because it was too old. I spent a lot of time researching and documenting this proposal, and I still think it is very relevant.

**Library Affected:**
*workbox-expiration*

**Issue or Feature Request Description:**
Hi there! Thanks for making this incredibly useful tool :)

I have a bunch of use cases where I need to either update a resource periodically or where I need to remove a resource that hasn't been used for a while. The `ExpirationPlugin` with `maxAgeSeconds` can _sort of_ solve these use cases, but it isn't elegant and it has many bad edge cases.

I have tried to fix my use cases by making some custom plugins, but it is very complicated and requires a lot of IndexedDB calls. I then realised that 95% of the code I need has already been written for the `maxAgeSeconds` parameter, so maybe I should just propose some minor updates to workbox instead. And now that I have thought it through, I actually think this could solve a long list of challenges that would otherwise require custom code.

I will start with my proposed additions, then show an example. I am happy to discuss this in more detail, or provide more detailed use cases if you'd like :)

## Proposed additions
The `ExpirationPlugin` gets two new parameters in its config:

#### `maxUnusedSeconds` _number_
This will be almost identical to `maxAgeSeconds`, but instead of calculating the time since the resource was last fetched, it calculates the time since the resource was last used on the website. In other words, how long ago was a `request` made for the cached resource.
As with `maxAgeSeconds`, if the resource hasn't been used for that amount of time, it is removed from the cache.

#### `updateStale` _boolean_
When a cached resource is older than `maxAgeSeconds`, it will normally be removed from the cache, but if `updateStale` is set to true, the plugin will instead try to refetch and update the cached resource. If the update fails, the old resource is kept.
_This parameter does not affect removals caused by `maxEntries` or `maxUnusedSeconds`._

## Example: A better image caching recipe
[The default image caching recipe](https://developers.google.com/web/tools/workbox/guides/common-recipes#caching_images) shows a simple "cache this for 30 days, then delete" use case.

Let's consider that plugin setup:
```js
new ExpirationPlugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
}),
```
..vs a default plugin setup that leverages the proposed options:
```js
new ExpirationPlugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
updateStale: true,
maxUnusedSeconds: 30 * 24 * 60 * 60, // 30 Days
})
```

Imagine that a user has been looking at an image every day for some time, but loses their internet connection 28 days after they saw the image for the first time, and the connection ends up being down for 7 days.

With the current setup, the image disappears 2 days after the internet goes down, and is missing for 5 days until the internet comes back up. There was no reason to delete the image, so this is not ideal.
With the proposed setup, there will be a failed attempt at updating the image after 2 days, but since it was very recently seen, it will be kept for 5 days until it can eventually be updated.

Now imagine that the image is completely static and never requires updates, and that the user has this app for 5 years.

With the current setup, the app must delete the image once every 30 days, so it will have to download identical copies of the image 120 times. It isn't possible to fix this, because we want the image to expire if it isn't used.
With the proposed setup, this would not be nearly as big a problem, because the image can be `ETag` validated, meaning it won't be downloaded again if the server copy hasn't changed.

With the proposed setup, it would also be possible to change the setup slightly so that no network activity occurs _at all_ for all 5 years:
```js
new ExpirationPlugin({
maxEntries: 60,
maxUnusedSeconds: 30 * 24 * 60 * 60, // 30 Days
})
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.