Develope/React

CRA(Create React App) 서비스워커(ServiceWorker) 커스텀

oper0116 2020. 6. 13. 09:44
반응형

개요

CRA(Create React App)를 통하여 생성된 프로젝트는 서비스 워커(serviceWorker) 기능을 제공합니다.
CRA에서 기본적으로 제공되는 service-worker.js파일은 아래와 같습니다.

기본적으로 제공되는 service-worker.js

CRA에서 서비스워커를 재구성하는 방법은 여러 가지 방법이 있겠지만 workbox를 사용하여 서비스워커를 재구성하는 방법을 설명하고자 합니다.

환경 구성

프로젝트 생성

CRA를 사용하여 프로젝트를 생성합니다.

npx create-react-app rca-workbox-customize-deploy

모듈 설치

workbox-build, npm-run-all 모듈을 설치합니다.

npm install --save-dev workbox-build npm-run-all

workbox-build 모듈

서비스 워커에서 사용할 service-worker.js 파일을 재정의할 때 사용하기 위하여 해당 모듈을 설치합니다.

npm-run-all 모듈

package.json의 스크립트를 작성하기 위하여 해당 모듈을 설치합니다.

파일 생성

CRA로 생성한 프로젝트에서 src폴더 안에 sw-build.js, sw-custom.js파일을 생성

precaching 될 리소스 파일 경로 및 리스트의 수정이 필요한 것을 직접 작성하였기 때문에 workbox-buildinjectMenifest를 사용하였습니다. 좀 더 자세한 내용을 확인하시고 싶으신 분은 module-workbox-webpack-plugin.InjectManifest에서 확인 부탁드립니다.

index.js에서 serviceWorker를 사용 및 업데이트 시 postMessage를 전달하도록 코드를 작성합니다.

// serviceWorker.unregitser();
serviceWorker.register({
  onUpdate: registration => {
    if (registration.waiting) {
      registration.waiting.postMessage({ type: 'SKIP_WAITING' });
    } else {
      window.location.reload();
    }
  },
});

생성된 sw-build.js에 다음과 같이 코드를 작성합니다.

const workboxBuild = require('workbox-build');

const buildSW = () => {
  return workboxBuild
    .injectManifest({
      globDirectory: 'build',
      globPatterns: ["**/*.{js,css,html,png,jpg,svg}"],
      swDest: 'build/sw.js', // 빌드가 완료된 후 생성되는 파일 위치
      swSrc: 'src/sw-custom.js' // 커스텀할 service-worker.js 파일
    })
    .then(({ count, size, warnings }) => {
      // Optionally, log any warnings and details.
      // warnings.forEach(console.warn);
    });
};
buildSW();

sw-custom.js의 파일에는 workbox전략라우팅을 원하시는 방향으로 작성하시면 됩니다.

/* eslint-disable no-undef */
/* eslint-disable no-restricted-globals */
if ("function" === typeof importScripts) {
  importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js');

  // Global workbox
  if (workbox) {
    console.log("Workbox is loaded");

    // Disable logging
    workbox.setConfig({ debug: false });

    self.addEventListener('message', event => {
      if (event.data && event.data.type === 'SKIP_WAITING') {
        self.skipWaiting();
      }
    })

    // Manual injection point for manifest files.
    // All assets under build/ and 5MB sizes are precached.
    workbox.precaching.precacheAndRoute([]);

    // js caching
    workbox.routing.registerRoute(
      /\.js$/,
      new workbox.strategies.NetworkFirst({
        cacheName: 'js',
      })
    );

    // css cacing
    workbox.routing.registerRoute(
      /\.css$/,
      new workbox.strategies.NetworkFirst({
        cacheName: 'css',
      })
    );

    // font caching
    workbox.routing.registerRoute(
      new RegExp("https://fonts.(?:.googlepis|gstatic).com/(.*)"),
      new workbox.strategies.NetworkFirst({
        cacheName: 'fonts',
      })
    );

    // image caching
    workbox.routing.registerRoute(
      /\.(?:png|gif|jpg|jpeg|svg)$/,
      new workbox.strategies.NetworkFirst({
        cacheName: 'images',
      })
    );

  } else {
    console.error("Workbox could not be loaded. No offline support");
  }
}

스크립트 구성

package.json의 스크립트를 정리하기 위하여 npm-run-all 모듈을 설치 후 아래와 같이 스크립트 코드를 변경합니다.

...
"build": "npm-run-all build-js clean-cra-sw build-sw ",
"build-js": "react-scripts build",
"clean-cra-sw": "rm -f build/precache-manifest.*.js && rm -f build/service-worker.js",
"build-sw": "node ./src/sw-build.js"
...

npm run build이후 생성된 build폴더 내에 파일을 서빙하여 실행 시 아래와 같이 사용되는 리소스 파일이 캐시 되는 것을 확인할 수 있습니다.

css파일에서 사용되는 리소스 파일을 캐시

결론

CRA를 사용하여 생성된 프로젝트를 eject 하여 직접 service-worker.js파일을 변경할 수 있으나, eject를 사용하여 변경하기에는 CRA에서 제공하는 이점을 사용할 수 없기 때문에, 위와 같은 과정을 통해 재구성하였습니다.
해당 과정이 적용된 프로젝트는 여기에서 확인 가능합니다.

반응형