티스토리 뷰

 

 

이번 프로젝트에서는 PWA를 이용해서 앱처럼 보이는 효과를 적용하다가 ServiceWorker라는 개념을 몰라 정리해보았습니다.

(PWA를 활용하면 사파리등 웹에서 볼 수 있는 페이지를 홈 화면에 추가한 후 어플처럼 볼 수 있습니다.)

 

Google의 Workbox는 자산을 쉽게 캐시하고 프로그레시브 웹 앱 (PWA)을 빌드하는 데 사용되는 기능을 최대한 활용할 수 있도록 하는 라이브러리 및 node module 세트입니다.

 

 

서비스 워커(Service Worker)는 브라우저가 백그라운드에서 실행하는 스크립트입니다.

웹 페이지와 별개로 생명주기를 갖고 동작합니다.

 

서비스 워커는 오프라인(offline)에서  웹페이지를 사용자에게 보여주기 위해 만들어졌습니다.

 

서비스 워커의 장점

 

1. 브라우저에서 파일을 캐시할 수 있다.

2. Request를 가로채 Proxy Server와 비슷하게 동작합니다.

 

주의

 

ServiceWorker 적용 전 알아두어야할 점은 서비스워커는 보안상의 이유로 HTTPS에서만 실행이 됩니다.

 

 

파일구조

 

파일구조 같은 경우 pulic 폴더 안에 만들어주시면 됩니다.

저는 service-worker.js만 만들어 저기에 코드를 넣어줄겁니다.

 

(나머지 sw.js, workbox~.js 같은 파일은 무시해주세요 build시 자동으로 생성되는 파일들입니다.

저는 build를 해서 자동으로 만들어진 파일들입니다.)

 

적용

 

서비스 워커의 동작을 정의할 파일은 sw.js 입니다.

해당 파일은 custom file로 설정할 수 있으며 nextjs와 react에서 설정하는 방법이 조금 다르므로 참고해주세요.

 

 

https://test/sw.js 라는 경로에 sw.js 파일이 있을 때, 서비스 워커는 https://test/**/* 에 해당하는 모든 파일에 대해 적용 됩니다.

 

Nextjs 기준으로 설명하겠습니다.

 

1. app.js 에 워커를 등록하는 코드를 추가합니다.

 

if ('serviceWorker' in navigator) { // 서비스 워커 지원 확인
        navigator.serviceWorker.register('/sw.js'); // 서비스 워커 등록
}

 

저는 파일명을 다르게 만들었습니다 service-worker.js로 만들었지만 sw.js와 같다고 생각하시면 됩니다.

 

service-worker가 잘 등록되었는지 확인하기 위해 service-worker.js 파일을에 console.log를 찍어봅니다.

 

service-worker.js

console.log("test")

 

프로젝트 실행 후 개발자 도구에서 다음 탭에서 보면 성공적으로 서비스 워커가 등록된 것을 볼 수 있습니다.

단순히 등록만 되었지 아직 기능 따윈 없는 상태입니다.

 

 

서비스워커 사용(Workbox 이용)

 

서비스 워커를 이용해 static file 캐싱을 구현해보겠습니다.

 

여기에서는 Workbox라는 개념이 등장하는데, Workbox는 ServiceWorker를 간결하게 사용하기 위한 라이브러리로 생각하시면 됩니다.

 

Nextjs 같은 경우 next.config.js 파일안에 따로 설정을 해줘야합니다.

 

먼저 next workbox 전용 라이브러리를 설치해줍니다. 저는 다른 라이브러리도 같이 사용하기 때문에 다른 라이브러리도 있는데 무시해주시면 됩니다!

 

npm i next-with-workbox
 
// at next.config.js
const withWorkbox = require("next-with-workbox");
module.exports = withWorkbox({
  workbox: {
   // .
   // ..
   // ... any workbox-webpack-plugin.GenerateSW option
  },
  // .
  // ..
  // ... other Next.js config values
});

 

 

이미지 캐시 적용

 

service-worker.js

registerRoute(
  /\.(?:png|gif|jpg|jpeg|svg)$/,
  new CacheFirst({
    cacheName: 'images',
    plugins: [
      new ExpirationPlugin({
        maxEntries: 10,
        maxAgeSeconds: 60 * 60 * 24 * 7, // 7 Days
      }),
    ],
  }),
);

 

workbox는 Proxy를 이용해 모듈을 비동기적으로 로딩하기 때문에 전역에 선언해 모듈 로딩을 완료하는 것을 권장합니다.

 

registerRoute는 라우터를 등록하는 함수로 정규식을 만족하는 리소스에 대해 캐싱 전략을 적용합니다.

cachefirst는 리소스를 브라우저 캐시에서 먼저 찾아본 후, 없으면 네트워크를 이용해 파일을 다운하는 방식입니다.

 

이미지 등의 정적 파일은 변경되는 경우가 적고 용량이 크기 때문에 cachefirst로 최대한 캐시를 활용하는 것이 유리합니다.

 

기타 캐싱전략 참고

https://developer.chrome.com/docs/workbox/#use-cases-and-recipes

 

Workbox - Chrome Developers

Production-ready service worker libraries and tooling.

developer.chrome.com

 

확인

 

위 방법의 장점은 파일을 다운하지 않고 캐시에서 가져오기 때문에 페이지 로딩 속도 개선에 도움을 줍니다.

 

 

폰트 캐시 적용

core.clientsClaim();
core.skipWaiting();

// Cache Google Fonts
registerRoute(
  /^https:\/\/fonts\.gstatic\.com/,
  new CacheFirst({
    cacheName: 'google-fonts-webfonts',
    plugins: [
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
      new ExpirationPlugin({
        maxAgeSeconds: 60 * 60 * 24 * 365, // 365 Days
      }),
    ],
  }),
);

// Cache JavaScript and CSS
registerRoute(/\.(?:js|css)$/, new StaleWhileRevalidate());