본문 바로가기

[Nuxt3 / PWA] service worker로 앱 오프라인 캐싱하기

[Nuxt3 / PWA] service worker로 앱 오프라인 캐싱하기

vue에서 내 상황에 적합한 레퍼런스를 찾지 못해 아쉬웠던 기억이 있기에 비슷한 상황일 분들을 위해 글을 작성해둔다.

 

Nuxt3 프레임워크 기반의 프로젝트에서 service-worker로 오프라인 캐싱을 구현해보았다. 

 

서비스 워커란?

서비스 워커는 웹 앱의 동작을 고도화할 수 있는 이벤트 기반 워커로 JavaScript 파일의 형태를 가지고 있다. 즉, 웹 플랫폼이 네이티브의 앱 기능을 구현할 수 있도록 기능을 제공하며 보통은 아래의 상황을 구현할 수 있다. 

  • 백그라운드 데이터 동기화 
  • 다른 출처에서의 리소스 요청 응답
  • 위치 정보, 자이로 센서 등 계산에 높은 비용이 들어가는 다수의 페이지에서 함께 사용하기 위한 데이터 업데이트 중앙화
  • 특정 URL 패턴에 기반한 사용자 지정 템플릿 제공
  • 성능 향상 (사용자가 다음에 필요로 할 것으로 예상되는 리소스 프리페칭 등)
  • 푸쉬 메시지 전송
    • request 없이 서버에서 원할 때 respond를 할 수 있음
  • 특정 시간과 날짜에 반응 

 

오프라인 캐싱을 하는 이유

위에도 서술되었다시피 캐싱을 하면 네트워크가 느린 환경 또는 오프라인에서 앱을 사용할 수 있는 큰 장점이 있다. 즉 네이티브 앱과 비슷한 환경을 구현할 수 있는 것이다. 아래 구현 화면을 보면 더 이해하기 쉬울 것이다. 

 

오프라인 캐싱 구현 화면

적용된 화면은 아래와 같다.

상황 : 아래와 같이 서비스 워커가 우선 등록되어 있고 이미 온라인 상황에서 게시물 2개 중 한 개는 클릭하여 조회를 하고 나머지 한 개는 하지 않은 상황이다. 


그뒤, Offline 상태를 만들어 새로고침을 해보면 이미 GET 요청을 해서 받아온 자료들이 보이는 것을 알 수 있다. 

  • 또한 온라인일 때 클릭하여 조회했었던 게시글 1개는 오프라인 상태에서도 상세 내용을 확인할 수 있다. 
  • 하지만, 온라인일 때 조회하지 않았던 게시글은 무한로딩이 뜨는 것을 알 수 있다.

 

 

구현 코드

 

우선 @vite-pwa/nuxt 등 nuxt3과 관련된 라이브러리를 다 시도해보았지만 타입 에러, 호환 문제 등 다양한 이슈로 진행하지 않았다. 

(이렇게 한 줄로 서술하지만 굉장한 삽질이 있었다.. ㅠ) 

 

폴더 구조

우선 폴더 구조는 아래와 같이 되어 있다. 

 

 

서비스워커 등록하기

 

루트 폴더 안에 서비스 워커를 등록하는 파일을 생성해준다.

 

registerServiceWorker.js
  • process.env.NODE_ENV : Node.js 환경 변수 중 하나로 Node.js 애플리케이션 환경을 나타낸다.
    • 빌드 도구나 번들러를 통해 코드를 관리하고, 환경에 따라 다른 설정을 적용하기 위한 용도이다.
import { register } from "register-service-worker";

export function SW() {
    if (process.env.NODE_ENV === "production") {
        register(`/service-worker.js`, {
            ready() {
                console.log(
                    "App is being served from cache by a service worker.\n" +
                        "For more details, visit https://goo.gl/AFskqB",
                );
            },
            registered() {
                console.log("Service worker has been registered.");
            },
            cached() {
                console.log("Content has been cached for offline use.");
            },
            updatefound() {
                console.log("New content is downloading.");
            },
            updated() {
                console.log("New content is available; please refresh.");
            },
            offline() {
                console.log(
                    "No internet connection found. App is running in offline mode.",
                );
            },
            error(error) {
                console.error(
                    "Error during service worker registration:",
                    error,
                );
            },
        });
    }
}

 

 

우선 기존 레퍼런스 방식대로 해보았으나, 작동하지 않아서 App.vue의 onMounted 함수 안에 조건문을 사용해서 서비스워커가 등록될 수 있도록 코드를 작성해두었다. 

 

App.vue
<template>
    <v-app id="app">
        <NuxtLayout>
          .
          .
          .
        </NuxtLayout>
    </v-app>
</template>

<script setup>
import { SW } from "./registerServiceWorker";

onMounted(() => {
    if ("serviceWorker" in navigator) {
        SW();
    }
   .
   .
   .
});
</script>

 

오프라인 캐싱하기

등록된 Service Worker와 Workbox 라이브러리를 이용하여 오프라인 캐싱을 구현해보았다. 이로서 서비스 워커가 브라우저 백그라운드에서 실행되고, 네트워크 요청을 가로채서 캐시를 활용해 오프라인 상황에서도 앱 / 웹 페이지를 로드할 수 있게 된다. 

  • Workbox서비스 워커를 구성하고 관리하기 위한 라이브러리로 서비스 워커 캐싱 및 네트워크 전략을 구현하는 데 사용된다.
  • NetworkFirst는 네트워크 요청을 먼저 시도하고, 실패할 경우(오프라인 등) 캐시 데이터를 활용한다.

 

public/service-worker.js
const CACHE = "pwabuilder-offline";

importScripts(
    "https://storage.googleapis.com/workbox-cdn/releases/6.2.0/workbox-sw.js",
);

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

workbox.setConfig({ debug: false }); // 콘솔에 workbox 로그가 찍히지 않게 하기 위함 
workbox.routing.registerRoute(
    new RegExp("/*"),  // 모든 URL에서 
    new workbox.strategies.NetworkFirst({ // 오프라인 캐싱 전략 적용 
        cacheName: CACHE, 
    }),
);

 

 

레퍼런스 

https://developer.mozilla.org/ko/docs/Web/API/Service_Worker_API    

 

 

 

우선 오프라인 캐싱을 할 수 있는 좋은 레퍼런스를 소개한다. 이미 잘 구현되어 있는 레포지토리를 클론 받아서 진행하고 있는 프로젝트에 적용시켜도 좋을 듯 하다. 

 

https://developers.google.com/web/fundamentals/codelabs/offline?hl=ko 

 

프로그레시브 웹 앱: 오프라인으로 전환  |  Google for Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English 프로그레시브 웹 앱: 오프라인으로 전환 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

developers.google.com

 

728x90
⬆︎