Develope/개발일지

Workbox 캐싱기능을 사용한 PWA 개발

oper0116 2020. 6. 8. 20:36
반응형

개발 내용

웹앱 어플리케이션 프로젝트를 진행하며 workbox의 캐시 기능을 이용하여 PWA을 개발하였습니다.

어플리케이션 최초 구동 시 필요한 리소스의 캐시가 완료되면, 재실행시 캐시 된 리소스 파일들을 사용하여 오프라인 상태에서 사용할 수 있도록 개발을 진행하였습니다.

개발 환경 구성

workbox를 사용하기 위해서 workbox-build모듈을 설치 후 service-worker에서 사용될 serviceWorker.js파일을 생성하도록 하였습니다.

리소스 캐시

프로젝트 내에서 캐시 할 리소스를 필수적으로 캐시가 되어야 하는지, 사용자 또는 환경에 따라 캐시가 필요한 리소스로 구분을 지었습니다.
그리고 각 구분에 따라 캐시 하는 내용을 다르게 구성하였습니다.

필수적으로 캐시가 되어야 하는 리소스

해당 리소스는 js, css와 같이 어플리케이션을 구동함에 있어 필수적인 것들을 구분하였습니다.
필수적으로 캐시가 되어야 하는 리소스는 workbox-routing을 사용하여 캐싱될 수 있도록 하였습니다.
또한 추후 어플리케이션이 업데이트될 때 변경된 리소스 파일을 불러와야 하기 때문에 NetworkFirst 전략을 선택하였습니다.

...

workbox.routing.registerRoute(
  '/',
  new workbox.strategies.NetworkFirst({
    cacheName: 'home',
  })
);
//

...

사용자 또는 환경에 따라 캐시가 되어야 하는 리소스

사용자 또는 환경에 따라 캐시 되어야 하는 리소스는 사용자가 특정 액션을 취했을 때,
캐시 해야 할 리소스 리스트를 전달하여 해당 리스트에 있는 리소스 파일을 캐시 하도록 진행하였습니다.

먼저 service-workerclient 간의 통신을 위해서 postMessage 인터페이스를 구성하여 사용하였습니다.

// index.js
public sendToMessage = async (params) => {
  return new Promise((resolve, reject) => {
    const channel = new MessageChannel();

    channel.port1.onmessage = event => {
      if (event.data.error) {
        reject(event.data.error);
      } else {
        resolve(event.data);
      }
    };

    if ('serviceWorker' in navigator) {
      if (navigator.serviceWorker.controller) {
        navigator.serviceWorker.controller.postMessage(params, [channel.port2]);
      }
    }
  });
};

// service-worker.js
function sendToMessageClient(type, params) {
  const event = { type, params };
  this.clients.matchAll().then(clients => {
    clients.forEach(client => client.postMessage(JSON.stringify(event)));
  });
}

클라이언트 페이지에서는 캐시가 필요한 리소스 리스트를 postMessage 인터페이스를 사용하여 RESOURCE_LIST를 호출합니다.

sendToMessage({ type: 'RESOURCE_LIST', resourceList: ['../resources/1.png', '../resources/2.png'] });

client에서 PostMesage RESOURCE_LIST 호출 시 전달받은 resourceList를 캐싱하도록 작업하였습니다.
또한 serviceWorker에서는 HTML DOM에 직접 접근이 불가함으로, client페이지에서 캐싱 과정의 화면처리를 위하여 캐싱 성공 여부를 PostMeesage로 전달하도록 하였습니다.

self.addEventListener('message', event => {
  if (event.data.type === 'RESOURCE_LIST') {
    cacheList = event.data.resourceList;
    event.waitUntil(
      caches
        .open(resource.key)
        .then(function(cache) {
          cacheList.forEach(async item => {
            cache
              .add(item)
              .then()
              .catch(function(e) {
              })
              .finally(function() {
                sendToMessageClient('ADD_CACHE', {});
              });
          });
        })
        .catch(function(e) {
        })
    );
  }
});

이러한 과정을 통해 어플리케이션을 구동하기 위한 리소스 파일 캐싱이 완료되었습니다.
이후 어플리케이션 실행 시 캐시 된 리소스 파일을 사용하는 걸 확인되었으며, 또한 어플리케이션 업데이트가 있다면 workboxNetworkFirst의 전략에 따라 네트워크를 통해 변경된 리소스를 먼저 조회하기 때문에 변경된 리소스 파일을 다시 캐싱하여 사용하게 되었습니다.

참고자료

(workbox)[https://developers.google.com/web/tools/workbox]

반응형

'Develope > 개발일지' 카테고리의 다른 글

QueryFunctionContext을 고민하면서..  (0) 2024.07.02