docs-serwist-runtime-caching.md
Original source (Apache 2.0 License). Adapted for Serwist’s usage.
Some assets in your web application may be infrequently used, very large, or vary based on the user’s device (such as responsive images) or language. These are instances where precaching may be an anti-pattern, and you should rely on runtime caching instead.
Serwist provides these strategies out of the box:
You may also write your own strategy as detailed in Caching strategies: Creating a new strategy.
The Serwist class exposes the registerCapture method to allow you to match a pattern of routes to a caching strategy. registerCapture accepts two arguments:
Strategy.You may also use the runtimeCaching option of Serwist's constructor. It is essentially a syntactic sugar for registerCapture.
When the service worker intercepts a network request, Serwist tries to match the URL of the request to one of the registered handlers, which will then be used to generate a response. In the following example, we register a route that matches incoming same-origin image requests, applying the CacheFirst strategy.
sw.ts
import { CacheFirst, Serwist } from "serwist";
const serwist = new Serwist();
serwist.registerCapture(({ request, sameOrigin }) => {
return sameOrigin && request.destination === "image";
}, new CacheFirst());
serwist.addEventListeners();
Serwist allows you to bucket cached responses into separate Cache instances using the cacheName option available in the built-in strategies. In the following example, images use the StaleWhileRevalidate strategy, whereas CSS and JavaScript assets use the CacheFirst strategy. The route for each asset places responses into separate caches, by adding the cacheName property.
sw.ts
import { CacheFirst, StaleWhileRevalidate, Serwist } from "serwist";
const serwist = new Serwist({
runtimeCaching: [
// Handle images
{
matcher({ request }) {
return request.destination === "image";
},
handler: new StaleWhileRevalidate({
cacheName: "images",
}),
},
// Handle scripts
{
matcher({ request }) {
return request.destination === "script";
},
handler: new CacheFirst({
cacheName: "scripts",
}),
},
// Handle styles
{
matcher({ request }) {
return request.destination === "style";
},
handler: new CacheFirst({
cacheName: "styles",
}),
},
],
});
serwist.addEventListeners();
The interaction of your service worker with cross-origin assets is considerably different from with same-origin assets. Cross-Origin Resource Sharing (CORS) is complicated, and that complexity extends to how you handle cross-origin resources in a service worker.
When making a cross-origin request in no-cors mode, the response can be stored in a service worker cache and even be used directly by the browser. However, the response body itself can’t be read via JavaScript. This is known as an opaque response.
Opaque responses are a security measure intended to prevent the inspection of a cross-origin asset. You can still make requests for cross-origin assets and even cache them, you just can’t read the response body or even read its status code!
Even if you load cross-origin assets that do set permissive CORS headers that allow you read responses, the body of cross-origin response may still be opaque. For example, the following HTML will trigger no-cors requests that will lead to opaque responses regardless of what CORS headers are set:
index.html
<link rel="stylesheet" href="https://example.com/path/to/style.css">
To explicitly trigger a cors request that will yield a non-opaque response, you need to explicitly opt-in to CORS mode by adding the crossorigin attribute to your HTML:
index.html
<link crossorigin="anonymous" rel="stylesheet" href="https://example.com/path/to/style.css">
This is important to remember when your service worker cache subresources loaded at runtime.
By default, Serwist takes a cautious approach to caching opaque responses. As it’s impossible to examine the status code of opaque responses, caching an error response can result in a persistently broken experience if a cache-first or cache-only strategy is used.
If you need to cache an opaque response in Serwist, you should use a network-first or stale-while-validate strategy to handle it. This ensures that failed responses won’t persist, and will eventually be replaced by usable responses.
If you use another caching strategy and an opaque response is returned, Serwist will warn you that the response wasn’t cached when in development mode.
If you are absolutely sure that you want Serwist to cache an opaque response using a cache-first or cache-only strategy, you can do so using CacheableResponse or CacheableResponsePlugin.
To avoid leakage of cross-domain information, there’s a significant padding added to the size of an opaque response when calculating storage quota limits. This affects how navigator.storage reports storage quotas.