사전 캐싱 없이 Workbox 사용

지금까지 이 문서는 사전 캐싱에 중점을 두었으며 generateSWinjectManifest 빌드 도구를 주로 다루었습니다. 서비스 워커에 미리 캐싱 로직을 포함하는 데는 여러 가지 좋은 이유가 있지만 Workbox를 사용하기 위해 미리 캐싱을 사용할 필요는 없습니다.

프로젝트에 런타임 캐싱만 필요할 수도 있고, 웹 푸시와 같은 서비스 워커 API를 더 깔끔한 방법으로 통합하고 싶을 수도 있습니다. 이러한 경우는 Workbox의 빌드 도구를 사용하지 않을 때이며, 이 도움말에서는 이러한 내용을 다룹니다.

번들러를 사용하는 경우

번들러는 웹 개발 환경에서 중요한 역할을 하며 프로젝트에서 번들러를 사용하고 있을 가능성이 높습니다. 이 경우 아무것도 미리 캐시하지 않는다면 번들러 플러그인 (예: workbox-webpack-plugin)을 사용할 필요가 없다는 점을 알아야 합니다. 애플리케이션에서 서비스 워커를 별도의 진입점으로 취급하게 됩니다.

프로젝트 소스 디렉터리의 루트에서 서비스 워커를 만들고 애플리케이션에 필요한 Workbox 모듈을 사용합니다. 다음은 미리 캐싱 없이 별도의 Cache 인스턴스에서 탐색 및 이미지 애셋 요청에 대한 캐싱 전략을 설정하는 예입니다.

// 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);

이제 선택한 번들러에서 이 서비스 워커를 진입점으로 지정하면 됩니다. 다음은 몇 가지 인기 있는 번들러에서 이를 실행하는 방법의 예입니다.

webpack

webpackentry 구성에서 진입점을 허용합니다. 이 접근 방식을 사용할 때는 다음 사항에 유의해야 합니다.

  1. 서비스 워커의 범위를 최대한 넓히려면 출력 디렉터리의 루트에 출력해야 합니다.
  2. 서비스 워커를 업데이트하면 새 해시가 생성되어 웹사이트에 여러 서비스 워커가 배포될 수 있으므로 서비스 워커에 버전이 지정되어서는 안 됩니다.

위 조건을 충족하기 위해 처리 중인 현재 진입점이 서비스 워커 진입점인지 검사하는 함수를 output.filename에 전달할 수 있습니다. 그렇지 않으면 버전 관리된 파일이 일반 대상에 쓰여집니다.

// 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
  }
};

롤업

롤업은 webpack과 비슷하지만 여러 진입점이 배열로 내보낸 별도의 구성 객체로 지정된다는 점이 다릅니다.

// 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는 간단한 명령줄 인터페이스를 제공합니다.

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

esbuild는 기본적으로 process.env.NODE_ENV를 'development'로, 축소가 사용 설정된 경우 'production'으로 대체합니다.

workbox-sw를 사용하는 번들러가 없음

프로젝트에서 번들러를 사용하지 않을 수도 있습니다. workbox-sw는 서비스 워커 내의 CDN에서 Workbox 런타임을 로드할 수 있으며, 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);

CDN에서 Workbox 런타임을 로드하는 것이 좋지 않은 것 같으면 로컬 URL로 workbox-sw를 사용할 수 있습니다.

결론

이제 미리 캐시하지 않고 Workbox를 사용하는 방법을 알게 되었으므로 더 이상 특정 번들러나 빌드 도구에 종속되지 않습니다. 따라서 관심 있는 Workbox의 런타임 캐싱 코드만 사용하여 서비스 워커를 유연하게 수작업으로 만들 수 있습니다.