Como usar o Workbox sem pré-armazenamento em cache

Até agora, esta documentação tem trabalhado bastante sobre o pré-armazenamento em cache, muitas vezes abordando as ferramentas de build generateSW e injectManifest. Embora haja várias boas razões para incluir a lógica de pré-armazenamento em cache no seu service worker, não é necessário usar o pré-armazenamento em cache para usar o Workbox.

Talvez seu projeto precise apenas de armazenamento em cache do ambiente de execução, ou talvez você queira uma maneira mais limpa de integrar APIs do service worker, como envio da Web. Esses são os casos em que você não vai querer usar as ferramentas de build do Workbox, e é isso que abordamos neste artigo.

Ao usar um bundler

Bundlers são proeminentes no cenário de desenvolvimento da Web, e há uma boa chance de que seu projeto use um. Nesse caso, é importante saber que você não precisa usar um plug-in do bundler (como workbox-webpack-plugin) se não estiver fazendo o armazenamento prévio em cache. Você vai tratar o service worker como um ponto de entrada separado no aplicativo.

Na raiz do diretório de origem do projeto, crie um service worker e use os módulos do Workbox que seu aplicativo exigir. Confira um exemplo sem pré-armazenamento em cache que configura estratégias de armazenamento em cache para solicitações de recursos de navegação e imagem em instâncias de Cache separadas:

// sw.js
import {NetworkFirst, CacheFirst} from 'workbox-strategies';
import {registerRoute, NavigationRoute, Route} from 'workbox-routing';

const navigationRoute = new NavigationRoute(new NetworkFirst({
  cacheName: 'navigations'
}));

const imageAssetRoute = new Route(({request}) => {
  return request.destination === 'image';
}, new CacheFirst({
  cacheName: 'image-assets'
}));

registerRoute(navigationRoute);
registerRoute(imageAssetRoute);

A partir daqui, é uma questão de especificar esse service worker como um ponto de entrada no bundler de sua escolha. Confira abaixo alguns exemplos de como fazer isso com os bundlers mais usados.

Pacote da web

O webpack aceita pontos de entrada na configuração do entry. Há algumas coisas que você precisa saber ao usar essa abordagem:

  1. Para garantir que o service worker tenha o escopo mais amplo possível, é recomendável que ele seja enviado para a raiz do diretório de saída.
  2. Não convém que o service worker tenha controle de versão, já que as atualizações dele vão gerar novos hashes que podem resultar na implantação de vários service workers no seu site.

Para atender às condições acima, uma função pode ser transmitida para output.filename, que examina se o ponto de entrada atual que está sendo processado é o ponto de entrada do service worker. Caso contrário, os arquivos com controle de versão serão gravados nos destinos normais.

// webpack.config.js
import process from 'process';

const isProd = process.env.NODE_ENV === 'production';

export default {
  mode: isProd ? 'production' : 'development',
  context: process.cwd(),
  entry: {
    // Service worker entry point:
    sw: './src/sw.js',
    // Application entry point:
    app: './src/index.js'
  },
  output: {
    filename: ({runtime}) => {
      // Check if the current filename is for the service worker:
      if (runtime === 'sw') {
        // Output a service worker in the root of the dist directory
        // Also, ensure the output file name doesn't have a hash in it
        return '[name].js';
      }

      // Otherwise, output files as normal
      return 'js/[name].[contenthash:8].js';
    },
    path: './dist',
    publicPath: '/',
    clean: true
  }
};

consolidação

Rollup é uma situação semelhante ao webpack, exceto que vários pontos de entrada são especificados como objetos de configuração separados exportados em uma matriz:

// rollup.config.js
import { nodeResolve } from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';

// Plugins common to both entry points
const plugins = [
  nodeResolve(),
];

export default [
  // Application entry point
  {
    input: './src/index.js',
    output: {
      dir: './dist/js',
      format: 'esm'
    },
    plugins
  },
  // Service worker entry point
  {
    input: './src/sw.js',
    output: {
      file: './dist/sw.js',
      format: 'iife'
    },
    plugins: [
      ...plugins,
      // This @rollup/plugin-replace instance replaces process.env.NODE_ENV
      // statements in the Workbox libraries to match your current environment.
      // This changes whether logging is enabled ('development') or disabled ('production').
      replace({
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
      })
    ]
  }
];

esbuild

esbuild oferece uma interface de linha de comando direta:

npx esbuild ./src/sw.js --bundle --minify --outfile=./dist/sw.js

O esbuild fará a substituição de process.env.NODE_ENV por "development" por padrão ou "production" se a minificação estiver ativada.

Sem um bundler usando workbox-sw

Talvez seu projeto nem use um bundler. O workbox-sw pode carregar o ambiente de execução do Workbox para você de uma CDN no seu service worker e sem uma etapa de criação se você importá-lo com importScripts:

// sw.js

// Imports Workbox from the CDN. Note that "6.2.0" of the URL
// is the version of the Workbox runtime.
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.2.0/workbox-sw.js');

const navigationRoute = new workbox.routing.NavigationRoute(new workbox.strategies.NetworkFirst({
  cacheName: 'navigations'
}));

const imageAssetRoute = new workbox.routing.Route(({request}) => {
  return request.destination === 'image';
}, new workbox.strategies.CacheFirst({
  cacheName: 'image-assets'
}));

workbox.routing.registerRoute(navigationRoute);
workbox.routing.registerRoute(staticAssetRoute);

Se a perspectiva de carregar o ambiente de execução do Workbox a partir de uma CDN não parecer boa, é possível usar workbox-sw com URLs locais.

Conclusão

Agora que você sabe como usar o Workbox sem armazenamento prévio em cache, não fica mais preso a um bundler ou ferramenta de build específico. Isso dá a flexibilidade de criar um service worker usando apenas os bits do código de armazenamento em cache do ambiente de execução do Workbox em que você tem interesse.