Alguns recursos no seu aplicativo da Web podem ser usados com pouca frequência, muito grandes ou variam de acordo com o dispositivo (como imagens responsivas) ou o idioma do usuário. Essas são instâncias em que o pré-armazenamento em cache pode ser um antipadrão. Em vez disso, use o armazenamento em cache no ambiente de execução.
No Workbox, é possível processar o armazenamento em cache no ambiente de execução para recursos usando o módulo workbox-routing
para associar rotas e processar estratégias de armazenamento em cache para eles com o módulo workbox-strategies
.
Estratégias de armazenamento em cache
É possível processar a maioria das rotas para recursos com uma das estratégias integradas de armazenamento em cache. Eles são abordados em detalhes anteriormente nesta documentação, mas veja alguns que vale a pena recapitular:
- Desatualizado durante a revalidação: usa uma resposta armazenada em cache para uma solicitação (se disponível) e atualiza o cache em segundo plano com uma resposta da rede. Portanto, se o recurso não estiver armazenado em cache, ele vai aguardar a resposta da rede e usá-lo. É uma estratégia bastante segura, porque atualiza regularmente as entradas de cache que dependem dele. A desvantagem é que ela sempre solicita um recurso da rede em segundo plano.
- Prioridade à rede tenta conseguir uma resposta da rede primeiro. Se uma resposta é recebida, ele a passa para o navegador e a salva em um cache. Se a solicitação de rede falhar, a última resposta armazenada em cache será usada, permitindo o acesso off-line ao recurso.
- Cache First verifica o cache em busca de uma resposta primeiro e a usa se disponível. Se a solicitação não estiver no cache, a rede será usada, e qualquer resposta válida será adicionada ao cache antes de ser passada para o navegador.
- Somente rede força a resposta a vir da rede.
- Somente cache força a resposta a vir do cache.
É possível aplicar essas estratégias para selecionar solicitações usando métodos oferecidos por workbox-routing
.
Como aplicar estratégias de armazenamento em cache com correspondência de rota
workbox-routing
expõe um método registerRoute
para corresponder rotas e processá-las com uma estratégia de armazenamento em cache. registerRoute
aceita um objeto Route
, que, por sua vez, aceita dois argumentos:
- Uma string, expressão regular ou um callback de correspondência para especificar critérios de correspondência de rota.
- Um gerenciador para a rota, normalmente uma estratégia fornecida por
workbox-strategies
.
Os callbacks de correspondência têm preferência para corresponder às rotas, porque fornecem um objeto de contexto que inclui o objeto Request
, a string do URL de solicitação, o evento de busca e um booleano indicando se a solicitação é da mesma origem.
Em seguida, o manipulador processa a rota correspondente. No exemplo a seguir, é criada uma nova rota que corresponde às solicitações de imagem da mesma origem, aplicando o cache primeiro, recorrendo à estratégia de rede.
// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
// A new route that matches same-origin image requests and handles
// them with the cache-first, falling back to network strategy:
const imageRoute = new Route(({ request, sameOrigin }) => {
return sameOrigin && request.destination === 'image'
}, new CacheFirst());
// Register the new route
registerRoute(imageRoute);
Como usar vários caches
O Workbox permite agrupar respostas armazenadas em cache em instâncias de Cache
separadas usando a opção cacheName
disponível nas estratégias agrupadas.
No exemplo a seguir, as imagens usam uma estratégia de inatividade durante a revalidação, enquanto os recursos de CSS e JavaScript usam uma estratégia de rede que prioriza o cache. A rota de cada recurso coloca respostas em caches separados, adicionando a propriedade cacheName
.
// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst, StaleWhileRevalidate } from 'workbox-strategies';
// Handle images:
const imageRoute = new Route(({ request }) => {
return request.destination === 'image'
}, new StaleWhileRevalidate({
cacheName: 'images'
}));
// Handle scripts:
const scriptsRoute = new Route(({ request }) => {
return request.destination === 'script';
}, new CacheFirst({
cacheName: 'scripts'
}));
// Handle styles:
const stylesRoute = new Route(({ request }) => {
return request.destination === 'style';
}, new CacheFirst({
cacheName: 'styles'
}));
// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);
registerRoute(stylesRoute);
Como definir uma expiração para entradas de cache
Esteja ciente das cotas de armazenamento ao gerenciar cache(s) do service worker. ExpirationPlugin
simplifica a manutenção do cache e é exposto por workbox-expiration
. Para usá-lo, especifique-o na configuração de uma estratégia de armazenamento em cache:
// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';
// Evict image cache entries older thirty days:
const imageRoute = new Route(({ request }) => {
return request.destination === 'image';
}, new CacheFirst({
cacheName: 'images',
plugins: [
new ExpirationPlugin({
maxAgeSeconds: 60 * 60 * 24 * 30,
})
]
}));
// Evict the least-used script cache entries when
// the cache has more than 50 entries:
const scriptsRoute = new Route(({ request }) => {
return request.destination === 'script';
}, new CacheFirst({
cacheName: 'scripts',
plugins: [
new ExpirationPlugin({
maxEntries: 50,
})
]
}));
// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);
O cumprimento das cotas de armazenamento pode ser complicado. Recomendamos considerar os usuários com pressão de armazenamento ou que querem usar o espaço da maneira mais eficiente. Os pares de ExpirationPlugin
do Workbox podem ajudar a alcançar essa meta.
Considerações sobre origem cruzada
A interação entre o service worker e os recursos de origem cruzada é consideravelmente diferente do que acontece com os recursos de mesma origem. O compartilhamento de recursos entre origens (CORS) é complicado, e essa complexidade se estende ao modo como você lida com recursos de origem cruzada em um service worker.
Respostas opacas
Ao fazer uma solicitação de origem cruzada no modo no-cors
, a resposta pode ser armazenada em cache em um service worker e até mesmo ser usada diretamente pelo navegador. No entanto, o corpo da resposta em si não pode ser lido por JavaScript. Isso é conhecido como resposta opaca.
As respostas opacas são uma medida de segurança destinada a impedir a inspeção de um recurso de origem cruzada. Ainda é possível fazer solicitações de recursos de origem cruzada e até mesmo armazená-los em cache. No entanto, não é possível ler o corpo da resposta nem o código de status.
Ative o modo CORS
Mesmo que você carregue recursos de origem cruzada que definam cabeçalhos CORS permissivos que permitam a leitura de respostas, o corpo da resposta de origem cruzada ainda poderá ficar opaco. Por exemplo, o HTML a seguir acionará solicitações no-cors
que levarão a respostas opacas, independentemente dos cabeçalhos CORS definidos:
<link rel="stylesheet" href="https://example.com/path/to/style.css">
<img src="https://example.com/path/to/image.png">
Para acionar explicitamente uma solicitação cors
que produza uma resposta não opaca, você precisa ativar explicitamente o modo CORS adicionando o atributo crossorigin
ao HTML:
<link crossorigin="anonymous" rel="stylesheet" href="https://example.com/path/to/style.css">
<img crossorigin="anonymous" src="https://example.com/path/to/image.png">
É importante lembrar disso quando as rotas no service worker armazenam em cache sub-recursos carregados no ambiente de execução.
A caixa de trabalho pode não armazenar respostas opacas em cache
Por padrão, o Workbox adota uma abordagem cautelosa para armazenar respostas opacas em cache. Como é impossível examinar o código de resposta em busca de respostas opacas, o armazenamento em cache de uma resposta de erro pode resultar em uma experiência corrompida persistentemente se uma estratégia que prioriza o cache ou apenas o cache for usada.
Se você precisar armazenar uma resposta opaca no Workbox em cache, use uma estratégia que prioriza a rede ou a validação para obsoleto durante a execução. Sim, isso significa que o recurso ainda será solicitado da rede, mas garante que as respostas com falha não sejam mantidas e serão substituídas por respostas utilizáveis.
Se você usar outra estratégia de armazenamento em cache e uma resposta opaca for retornada, o Workbox avisará que a resposta não foi armazenada em cache no modo de desenvolvimento.
Forçar o armazenamento em cache de respostas opacas
Se você tiver absoluta certeza de que quer armazenar uma resposta opaca em cache usando uma estratégia que prioriza o cache ou apenas para o cache, force o Workbox a fazer isso com o módulo workbox-cacheable-response
:
import {Route, registerRoute} from 'workbox-routing';
import {NetworkFirst, StaleWhileRevalidate} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';
const cdnRoute = new Route(({url}) => {
return url === 'https://cdn.google.com/example-script.min.js';
}, new CacheFirst({
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200]
})
]
}))
registerRoute(cdnRoute);
Respostas opacas e a API navigator.storage
Para evitar o vazamento de informações entre domínios, há um preenchimento significativo adicionado ao tamanho de uma resposta opaca usada para calcular limites de cota de armazenamento. Isso afeta a forma como a API navigator.storage
informa as cotas de armazenamento.
Esse padding varia de acordo com o navegador. No entanto, para o Chrome, o tamanho mínimo que qualquer resposta opaca em cache contribui para o armazenamento total usado é de aproximadamente 7 megabytes. Tenha isso em mente ao determinar quantas respostas opacas você quer armazenar em cache, já que é possível exceder as cotas de armazenamento muito antes do esperado.