Invalidação de cache em cascata. Parte 2

Na primeira parte da tradução do material dedicado à invalidação do cache em cascata, discutimos a natureza do problema e consideramos uma das soluções para ele, que consiste no uso de cartões de importação. Sua vantagem é a facilidade de implementação. E menos - suporte ruim ao navegador. Hoje falaremos sobre outras maneiras de resolver esse problema.



Abordagem 2: Prestar serviços aos trabalhadores


A segunda solução para o problema é reproduzir a funcionalidade de cartões de importação usando um trabalhador de serviço.

Por exemplo, usando um trabalhador de serviço, você pode ouvir eventos que visam carregar materiais localizados em endereços correspondentes às chaves do cartão de importação. Executando essas solicitações, você pode fazer upload de arquivos cujos nomes incluem hashes de seu conteúdo:

 const importMap = {  '/main.mjs': '/main-1a2b.mjs',  '/dep1.mjs': '/dep1-b2c3.mjs',  '/dep2.mjs': '/dep2-3c4d.mjs',  '/dep3.mjs': '/dep3-d4e5.mjs',  '/vendor.mjs': '/vendor-5e6f.mjs', }; addEventListener('fetch', (event) => {  const oldPath = new URL(event.request.url, location).pathname;  if (importMap.hasOwnProperty(oldPath)) {    const newPath = importMap[oldPath];    event.respondWith(fetch(new Request(newPath, event.request)));  } }); 

No entanto, levando em conta o fato de que o código do trabalhador do serviço é fornecido acima, você precisa entender que esse código funcionará somente depois que o trabalhador do serviço estiver instalado e ativado. E isso significa que, quando você carregar o site pela primeira vez, serão solicitados arquivos sem hashes em seus nomes. Os arquivos com hashes nos nomes serão solicitados nos downloads subsequentes do site. Em outras palavras, aqui estamos lidando com o carregamento duplo de cada arquivo.

Se você levar isso em conta, pode parecer que o responsável pelo serviço não é uma solução adequada para o problema de invalidação de cache em cascata.

No entanto, aqui solicitarei que você me permita criticar brevemente as abordagens de longa data do cache. Vamos pensar no que acontece se pararmos de usar hashes de conteúdo nos nomes dos arquivos, em vez de colocar as informações de hash no código do operador de serviço.

É assim que ferramentas, como a Caixa de Trabalho, que recursos de pré-cache funcionam. Eles geram hashes do conteúdo de cada arquivo a partir da montagem e armazenam a correspondência dos nomes dos arquivos no trabalhador do serviço (é algo como um cartão de importação externo). Além disso, eles armazenam em cache recursos durante a primeira instalação de um trabalhador de serviço e adicionam ouvintes de eventos de fetch que retornam arquivos em cache em resposta a solicitações cujos endereços correspondem aos do mapa de importação.

Embora a ideia de que o cliente receba arquivos que não contêm informações sobre as versões de seu conteúdo possa parecer assustadora (e contradiga tudo o que você aprendeu), a solicitação para baixar o recurso correspondente é executada apenas quando o trabalhador do serviço está instalado. Solicitações adicionais para baixar esse recurso passam pela API de Armazenamento em Cache (que não usa cabeçalhos de armazenamento em cache), e novas solicitações para o servidor são executadas apenas quando uma nova versão do operador de serviço está sendo implantada (e você precisa, mesmo assim, de uma nova versão desses arquivos).

Como resultado, até você começar a implantar novas versões de módulos sem atualizar o trabalhador do serviço (e isso definitivamente não é recomendado), você nunca encontrará um conflito ou incompatibilidade de versão.

Para organizar o cache preliminar de arquivos usando a biblioteca de precaching da caixa de trabalho, você pode passar os endereços e as seqüências de arquivos com informações de versão desses arquivos para o método da biblioteca precacheAndRoute() :

 import {preacacheAndRoute} from 'workbox-precaching'; precacheAndRoute([  {url: '/main.mjs', revision: '1a2b'},  {url: '/dep1.mjs', revision: 'b2c3'},  {url: '/dep2.mjs', revision: '3c4d'},  {url: '/dep3.mjs', revision: 'd4e5'},  {url: '/vendor.mjs', revision: '5e6f'}, ]); 

Como exatamente gerar linhas com versões depende do próprio desenvolvedor. Mas se ele não quiser criá-los, a tarefa de gerar um manifesto pré-cache ajudará a simplificar os pacotes de construção de caixa de trabalho , workbox-cli e workbox-webpack-plugin (eles podem até gerar todo o código do operador de serviço).

Meu projeto de demonstração tem um exemplo de implementação de pré-cache usando um trabalhador de serviço em um aplicativo Rollup (usando workbox-cli ) e em um aplicativo webpack (usando workbox-webpack-plugin ).

Abordagem # 3: scripts personalizados para carregar recursos


Se o seu site não puder usar cartões de importação ou técnicos de serviço, aqui está a terceira abordagem para solucionar o problema. Consiste na implementação da funcionalidade de mapas de importação usando seu próprio script para carregar recursos.

Se você estiver familiarizado com os carregadores de módulo no estilo AMD (como SystemJS ou RequireJS ), também poderá saber que esses carregadores de módulo geralmente suportam aliases de módulo. De fato, o SystemJS suporta alias usando a sintaxe do mapa de importação. Como resultado, nosso problema é facilmente resolvido de forma que esta solução seja orientada para o futuro (e, além disso, funcionará em todos os navegadores existentes).

Se você usar Rollup, poderá definir a opção output.format como system . Nesse caso, a criação de um mapa de importação para o aplicativo será executada da mesma maneira descrita na descrição da primeira abordagem para solucionar o problema de invalidação de cache em cascata.

Meu aplicativo de demonstração tem um site de exemplo em que o Rollup é usado para criar materiais em um formato adequado para o SystemJS e criar um mapa de importação com o qual é possível baixar versões em hash dos arquivos.

▍Webpack e carregamento de recursos usando scripts


O Webpack também pode ajudá-lo a carregar recursos usando seu próprio script, mas o carregador gerado pelo webpack, diferentemente dos carregadores AMD clássicos, é exclusivo para cada pacote específico.

A vantagem dessa abordagem é que o tempo de execução do webpack pode (e realmente funciona) incluir seus próprios mapeamentos entre os nomes / identificadores dos fragmentos e seus endereços (isso é semelhante ao que recomendo aqui). Isso significa que os pacotes Webpack que usam a divisão de código têm menos probabilidade de sofrer invalidação de cache em cascata.

Na verdade, a boa notícia para os usuários do webpack é que, se eles configuraram corretamente o conjunto do projeto usando o webpack (dividindo o código em fragmentos, conforme descrito no guia de cache do webpack), uma alteração no código de um módulo individual não deve levar à invalidação mais de dois fragmentos (um é o que contém o módulo modificado, o segundo é o que contém o tempo de execução).

Mas tenho más notícias para quem usa o webpack para criar projetos. O fato é que o sistema de mapeamento interno desse empacotador não é padrão. Isso significa que não pode ser integrado às ferramentas existentes e que o usuário não pode configurá-lo. Por exemplo, você não pode gerar arquivos de saída independentemente (ou seja, faça o descrito na história sobre a primeira abordagem para resolver o problema) e coloque seus próprios hashes no mapeamento. E isso é um ponto negativo do webpack, porque os hashes usados ​​por esse pacote não são baseados no conteúdo dos arquivos de saída , mas no conteúdo dos arquivos de origem e na configuração da construção. E isso pode levar a erros pequenos e sutis (por exemplo - aqui , aqui e aqui - mensagens sobre esses erros).

Se você usar o webpack para criar um aplicativo que também use um trabalhador de serviço, recomendo o uso da estratégia workbox-webpack-plugin e cache, descrita na segunda abordagem para solucionar o problema. O plug-in gera hashes com base no conteúdo da saída do webpack, o que significa que você não precisa se preocupar com os erros acima. Além disso, trabalhar com nomes de arquivos que não possuem hashes é geralmente mais fácil do que trabalhar com nomes que possuem hashes.

Outros recursos do projeto da web


Anteriormente, eu falei sobre como trabalhar em programas JavaScript com nomes de arquivos "hash" contendo código de programa pode levar à invalidação de cache em cascata. Mas esse problema se aplica a outros materiais de projetos da web.

Portanto, os arquivos CSS e SVG geralmente se referem a outros recursos (imagens, por exemplo), cujos nomes podem conter informações sobre as versões dos arquivos correspondentes na forma de hashes. Como no caso de arquivos JS, para resolver o problema de invalidação de cache em cascata causado por alterações nos nomes de recursos semelhantes, você pode usar cartões de importação ou trabalhadores de serviço.

Para recursos como imagens e arquivos de vídeo, isso não é problema. Todas as recomendações existentes se aplicam aqui.

O principal aqui é lembrar que sempre, quando o arquivo A baixa o arquivo B e, além disso, inclui informações sobre a versão do arquivo B como um hash de seu conteúdo, a invalidação de cache do arquivo B também causa a invalidação de cache do arquivo A. trabalhando com recursos, cuja utilização é organizada de maneira diferente, você pode simplesmente ignorar os conselhos fornecidos neste material.

Sumário


Espero que este artigo tenha inspirado você a examinar mais de perto o seu site e descobrir se o problema da invalidação do cache em cascata o afeta. A maneira mais fácil de verificar isso é montando o site, alterando uma linha de código em um arquivo importado por vários módulos e, em seguida, reconstruindo o site. Se no diretório em que os resultados da montagem estão localizados, os nomes foram alterados para mais de um arquivo, isso significa que você tem um sinal de invalidação de cache em cascata. E, nesse caso, talvez seja necessário pensar em usar uma das abordagens descritas aqui para resolver esse problema em seu projeto.

Se falamos sobre o que é melhor escolher, então, francamente, isso depende de muito.

Quando os cartões de importação serão amplamente suportados pelos navegadores, enfrentaremos a maneira mais simples e perfeita de lidar com a invalidação de cache em cascata. Mas até que esse suporte esteja disponível, esse mecanismo não é aplicável na prática.

Se você já usa trabalhadores de serviço, especialmente se você usa a Caixa de Trabalho, recomendo a segunda das abordagens para resolver o problema discutido aqui. No site em que o original deste material foi publicado, a tarefa de cache preliminar de recursos foi resolvida dessa maneira.

Além disso, os trabalhadores do serviço são a única opção para aqueles que usam módulos JavaScript na produção. (E considerando que 98% dos meus usuários têm navegadores que oferecem suporte a trabalhadores de serviço e módulos JS, não foi difícil para mim escolher essa opção).

Se os trabalhadores do serviço não forem adequados para você, eu recomendaria a terceira das abordagens discutidas aqui, envolvendo o uso do SystemJS. Essa abordagem é melhor que outras, com base em scripts do gerenciador de inicialização, focados no futuro. A partir dele, será fácil mudar para importar cartões em um momento em que o suporte aparecerá em todos os navegadores.

Se falamos de produtividade, a escolha da direção de sua otimização depende de cada projeto específico. Antes de otimizar o desempenho, é importante medi-lo e decidir se há um problema e se é necessário lidar com ele. Se você liberar novas versões do projeto com pouca frequência e as alterações feitas no projeto geralmente forem em grande escala, o problema da invalidação do cache em cascata pode não ser relevante para você.

Por outro lado, se você costuma implantar pequenas alterações no projeto, os usuários que retornam podem ter o problema de carregar grandes quantidades de código que já existe em seus caches. Resolver esse problema significará um aumento significativo no desempenho do carregamento da página para esses usuários.

Caros leitores! A invalidação de cache em cascata afeta o seu projeto? Em caso afirmativo, diga-nos como você planeja resolvê-lo.


Source: https://habr.com/ru/post/pt472862/


All Articles