it-swarm-pt.tech

Ative o cache por meio de atualização em Angular 6 Service Worker

Estou tentando integrar o Angular Service Worker em um projeto existente. Se eu entendi corretamente, há dois casos em que os dados são armazenados em cache em Angular SW. É possível pré-buscar ou atualizar com atraso os dados do ativo e armazenar em cache chamadas de API específicas e outras solicitações XHR.

O que estou tentando alcançar é carregar primeiro um ativo específico via rede; se a solicitação exceder o tempo limite ou não estiver acessível, ela será atendida pelo cache. Assim como a estratégia freshness ao armazenar em cache chamadas de API. Mas parece que não há maneira possível de configurar esse mecanismo de carregamento de atualização para um arquivo JS que é carregado como um ativo no Angular. Configurei um exemplo de projeto para teste: - https://github.com/philipp-schaerer-lambdait/angular-service-worker-test

O exemplo a seguir é um aplicativo padrão Angular $ e não contém o projeto real com o qual estou trabalhando, mas mostra os elementos que eu gostaria de armazenar em cache, a estrutura fica assim:

\_ Angular root  
 |_ src/
   |_ index.html <----------- links to excluded_asset.js
   |_ app/
   |_ assets/
     |_ excluded_asset.js <-- this one is excluded in ngsw-config.json
     |_ included_asset.js
     |_ ...

Aqui as configurações relevantes:

ngsw-config.json

{
    "index": "/index.html",
    "assetGroups": [
        {
            "name": "app",
            "installMode": "prefetch",
            "resources": {
                "files": ["/favicon.ico", "/index.html", "/*.css", "/*.js"]
            }
        },
        {
            "name": "assets",
            "installMode": "lazy",
            "updateMode": "prefetch",
            "resources": {
                "files": ["/assets/**", "!/assets/excluded_asset.js"]
            }
        }
    ]
}

É possível obter um comportamento de armazenamento em cache como a estratégia freshness usando installMode e updateMode para os ativos?

Tentei excluí-lo do cache do ativo e ele foi carregado via rede, mas obviamente não será entregue pelo responsável pelo serviço depois de ficar offline.

Depois disso, tentei incluí-lo novamente por meio de dataGroups e definir a estratégia como freshness, mas parece que o ativo não será armazenado em cache novamente depois de excluído da configuração do ativo. Também não acho que as configurações de dataGroups possam ser usadas para este arquivo.

"dataGroups": [
    {
        "name": "config",
        "urls": ["assets/excluded_asset.js"],
        "cacheConfig": {
            "maxSize": 10,
            "maxAge": "1d",
            "timeout": "100",
            "strategy": "freshness"
        }
    }
}

Perdi alguma coisa ou não há como armazenar em cache um ativo por meio da estratégia freshness? Seria preferível não mover o arquivo ou alterar a forma como o arquivo está sendo solicitado.

EDITAR

Tentei movê-lo para fora dos diretórios de ativos em cache e incluí-lo na configuração dataGroups, também não funcionou.

15
Reizouko

Novo aplicativo com o responsável pelo serviço

O comando será o seguinte:

ng new myApp --service-worker (or using the alias — -sw )

Com este sinalizador de operador de serviço, Angular CLI 1.6 fará alguma automação para nós:

  1. O pacote Angular Service Worker será instalado.
  2. O suporte de compilação para NGSW será ativado.
  3. O NGSW será registrado para o seu aplicativo.
  4. O arquivo de configuração do NGSW será criado com alguns padrões inteligentes.

De qualquer forma, mesmo após o lançamento da CLI 1.6, é bom saber como reproduzir essas etapas, porque precisamos executá-las manualmente para adicionar o suporte NGSW ao aplicativo existente. Vamos adicionar Angular Service Worker ao PWAtter.

Adicionando Angular Service Worker ao aplicativo existente

Vamos executar manualmente as mesmas quatro etapas acima:

1. Instalar NGSW

npm install @angular/service-worker --save

2. Habilite o suporte à compilação (apenas para Angular CLI 1.6, veja o aviso abaixo)

ng set apps.0.serviceWorker=true

ou adicione/edite manualmente esse parâmetro em .angular-cli.json Arquivo.

Importante! Por enquanto, quando usamos o Angular CLI 1.5, verifique se você não possui essa propriedade em .angular-cli.json, causará erros de compilação. Veja como emular esta etapa em Angular CLI 1.5 abaixo).

3. Registre NGSW no seu AppModule. É assim que ficará em Angular CLI 1.6:

import { ServiceWorkerModule } from '@angular/service-worker'
import { environment } from '../environments/environment';

...

@NgModule({
  imports: [
    ...
    environment.production ? ServiceWorkerModule.register('/ngsw-worker.js') : []
  ],
  ...
})
export class AppModule { }

4. Crie o arquivo de configuração NGSW (o nome padrão é src/ngsw-config.json). Aqui está o conteúdo padrão que será gerado por Angular CLI 1.6.

{
  "index": "/index.html",
  "assetGroups": [{
    "name": "app",
    "installMode": "prefetch",
    "resources": {
      "files": [
        "/favicon.ico",
        "/index.html"
      ],
      "versionedFiles": [
        "/*.bundle.css",
        "/*.bundle.js",
        "/*.chunk.js"
      ]
    }
  }, {
    "name": "assets",
    "installMode": "lazy",
    "updateMode": "prefetch",
    "resources": {
      "files": [
        "/assets/**"
      ]
    }
  }]
}

No momento, enquanto usamos o Angular CLI 1.5, também precisamos emular o suporte à compilação a partir da etapa 2. Na verdade, existem duas ações extras que devem ser executadas além de ng build --prod comando (é importante usar a criação de produção para usar o NGSW!):

Gere o arquivo de controle (manifesto) NGSW ngsw.json com base no arquivo de configuração NGSW src/ngsw-config.json usando o NGSW CLI ngsw-config.

Copie o NGSW da pasta do pacote npm_modules para a pasta dist.

Para ter um comando simples para gerar build de produção com o suporte NGSW, vamos adicionar alguns scripts npm:

{
  ...
  "scripts": {
    ...
    "ngsw-config": "node_modules/.bin/ngsw-config dist src/ngsw-config.json",
    "ngsw-copy": "cp node_modules/@angular/service-worker/ngsw-worker.js dist/",
    "build-prod-ngsw": "ng build --prod && npm run ngsw-config && npm run ngsw-copy",
    "serve-prod-ngsw": "npm run build-prod-ngsw && http-server dist -p 8080"
  }
}

Agora, se executarmos npm run build-prod-ngsw teremos Angular PWA na pasta dist. Opcionalmente, poderíamos atendê-lo usando o mais simples http-server Correndo npm run serve-prod-ngsw.

Importante! Não use ng serve para testar seu Angular Service Worker. Este servidor de desenvolvimento não foi projetado para funcionar em colaboração com o fluxo do PWA. Sempre crie uma versão de produção do aplicativo e sirva-a na sua pasta de distribuição usando qualquer estática servidor web.

Shell de aplicativo

Se executarmos as ações acima e executarmos npm run build-prod-ngsw - o Angular em seu formato padrão está pronto para nós! Implante o aplicativo ou apenas execute-o localmente usando qualquer servidor Web estático (http-server pacote no meu caso, você executa npm run serve-prod-ngsw para construir e servir).

O aplicativo estará funcionando depois que ficamos offline. Por quê? Como o NGSW armazenou em cache todos os recursos listados na seção thsetsetGroups do arquivo de configuração e agora é responsável por servi-los no Armazenamento em Cache, que está cheio de registros agora:

enter image description here

O Operador de Serviço está registrado e ativo

enter image description here

Podemos visualizar o conteúdo da resposta em cache (disponível apenas em Chrome Canary no momento)

O NGSW usa o Armazenamento em cache para armazenar dados de respostas HTTP e alguns metadados para lidar com o controle de versão:

enter image description here

Tipos de armazenamento por NGSW

  • Entradas com postfix :cache - respostas HTTP reais.
  • Entradas com postfix :meta - para armazenar as meta informações da versão. Posteriormente, esse tipo de dados armazenados pode ser movido para indexedDB.

Se você mantiver o DevTools aberto, as entradas na seção Armazenamento em Cache provavelmente não serão atualizadas automaticamente após cada ação do lado do trabalhador de serviço. Se você deseja ver os dados reais, clique com o botão direito do mouse e escolha Atualizar caches.

Direita. O formulário padrão do arquivo de configuração NGSW não é suficiente para o nosso caso, porque usamos a fonte de ícones dos materiais. Obviamente, esses recursos (arquivos CSS e WOFF2 correspondentes) não foram armazenados em cache pelo NGSW, mas podemos corrigi-lo facilmente adicionando mais um grupo a assetGroups, além do padrão app e assets uns. Vamos chamá-lo de fonts:

{
  ...
  "assetGroups": [
   ...
   {
    "name": "fonts",
    "resources": {
      "urls": [
        "https://fonts.googleapis.com/**",
        "https://fonts.gstatic.com/**"
      ]
    }
  }]
}

Faz sentido especificar esses recursos usando a sintaxe globs porque a URL exata do arquivo de fonte pode mudar de tempos em tempos para oferecer suporte ao controle de versão da webfont. Além disso, você pode perceber que não especificamos installMode nem updateMode. Por um lado, ambos serão definidos como prefetch no arquivo de controle NGSW resultante, pois esse é um valor padrão. Por outro lado, eles serão armazenados em cache somente após serem solicitados, porque as especificidades de urls- maneira de listar os recursos.

Depois de reconstruir, executar e alternar para o modo offline, veremos o estado normal do aplicativo com todos os ícones no local.

No armazenamento em cache, veremos duas novas entradas:

enter image description here

Armazenamentos gerados pelo NGSW

Podemos até visualizar a fonte em cache:

enter image description here

Há uma diferença fundamental entre assetGroups e dataGroups.

  • assetGroups estão acompanhando a versão do aplicativo [Shell].
  • dataGroups são independentes da versão do aplicativo. Eles são armazenados em cache usando suas próprias políticas de cache e é a seção apropriada para lidar com nossas respostas da API.

Cache de tempo de execução

Para usar a estratégia Network-First para meus /timeline Terminal da API e estratégia Cache-First para o /favorites ponto final. A configuração correspondente em src/ngsw-config.json vai parecer:

{
  ...
  "dataGroups": [{
      "name": "api-freshness",
      "urls": [
        "/timeline"
      ],
      "cacheConfig": {
        "strategy": "freshness",
        "maxSize": 100,
        "maxAge": "3d",
        "timeout": "10s"
      }
    },
    {
      "name": "api-performance",
      "urls": [
        "/favorites"
      ],
      "cacheConfig": {
        "strategy": "performance",
        "maxSize": 100,
        "maxAge": "3d"
      }
    }
  ]
}

Existe uma opção principal que define o comportamento do NGSW: cacheConfig / strategy. Para estratégia de rede em primeiro lugar, é freshness, para cache em primeiro lugar - performance.

Agora crie, sirva, clique em Carregar minha linha do tempo e Carregar meus botões favoritos para obter e armazenar em cache as respostas da API e alterne para offline.

Sobre a otimização para o modo online. Volte para online e clique em Timeline / Favorites uma ou duas vezes. É claramente visível que os Favoritos são carregados imediatamente, apenas porque pulamos toda a viagem de rede e obtemos os dados do cache. Para especificar por quanto tempo armazenar em cache Usando as configurações na seção cacheConfig - nós temos o controle refinado lá.

O NGSW nos ajudou muito com algumas otimizações de rede realmente inteligentes, exigindo apenas algumas configurações JSON de nós.

5
Kousic

Eu tive o mesmo problema. A solução que encontrei para sempre ter arquivos js e css atualizados é simplesmente excluir o index.html dos ativos em cache.

{
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "updateMode": "prefetch",
      "resources": {
        "files": [
          "/*.css",
          "/*.js",
          "!/index.html" // Right here!!!!!
        ]
      }
    },
    {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "lazy",
      "resources": {
        "files": ["/static/**"]
      }
    }
  ]
}

Certifique-se de ter "outputHashing": "all", para sua angular configuração de compilação. Dessa forma, quando você altera seu código, ele gera um arquivo com um nome diferente. Em seguida, adiciona automaticamente a tag de script (ou tag de link) ) ao seu arquivo html (que o responsável pelo serviço ignorará) e assim que você enviar as alterações à produção, o index.html apontará para os novos arquivos js e css.

É claro que isso é péssimo de uma maneira muito óbvia: seu index.html não será armazenado em cache pelo responsável pelo serviço, mas pelo menos permitirá que os usuários que retornam tenham os arquivos mais atualizados.

Eu realmente desejei que houvesse uma maneira de ter uma opção de "frescura" para os ativos também ...

2
Etienne Talbot