AngelPlayer`s Diary

 

 

PWA(Progressive Web App)는 웹으로 개발된 서비스를 네이티브 앱과 같이 오프라인 작동, 설치 및 홈 화면 추가, 푸시 알림 등을 사용할 수 있도록 만들어 줍니다.

 

 

 

또한 모바일 뿐만 아니라 PC에서도 설치가 가능합니다.

 

PWA에는 Vue, React 등을 사용한다면 쉽게 프로젝트에 적용할 수 있습니다.

 

이번에는 React를 통해 만들어진 프로젝트에 PWA를 적용해보도록 하겠습니다.

 

 

 

 

1. 신규 React 앱 생성 시 PWA 템플릿 적용하기

서비스에 PWA를 적용하는 가장 편한 방법은 프로젝트 생성 시 PWA 템플릿을 사용하는 방법입니다.

 

 

$ npx create-react-app 프로젝트명 –template cra-template-pwa

기존 React 프로젝트 생성 방식에 말미에 –template cra-template-pwa를 붙임으로써 PWA 기능을 내장하는 React 앱을 생성할 수 있습니다.

 

 

 

 

2. 기존 React 앱에 PWA 적용하기

기존에 생성된 React 앱에 PWA를 적용하기 위해서는 2가지 파일에 코드를 작성하여야 합니다.

 

 

 

src- service-worker.js

// src/serviceWorker.js

const cacheName = 'my-app-cache-v1';
const cacheFiles = [
  '/', // 루트 경로
  '/index.html', // 인덱스 HTML 파일
  // 필요한 정적 리소스를 여기에 추가 (예: CSS, 이미지, JS 파일)
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(cacheName).then(cache => {
      return cache.addAll(cacheFiles);
    })
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      return response || fetch(event.request);
    })
  );
});

먼저 src- service-worker.js를 작성해주어야 합니다.

 

serviceWorker에는 오프라인 상황에서도 사용 가능하도록 구현하기 위해서 사용되는 이미지 등의 경로를 지정해주어야 합니다.

 

 

 

/* eslint-disable no-restricted-globals */

// This service worker can be customized!
// See https://developers.google.com/web/tools/workbox/modules
// for the list of available Workbox modules, or add any other
// code you'd like.
// You can also remove this file if you'd prefer not to use a
// service worker, and the Workbox build step will be skipped.

import { clientsClaim } from 'workbox-core';
import { ExpirationPlugin } from 'workbox-expiration';
import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';

clientsClaim();

// Precache all of the assets generated by your build process.
// Their URLs are injected into the manifest variable below.
// This variable must be present somewhere in your service worker file,
// even if you decide not to use precaching. See https://cra.link/PWA
precacheAndRoute(self.__WB_MANIFEST);

// Set up App Shell-style routing, so that all navigation requests
// are fulfilled with your index.html shell. Learn more at
// https://developers.google.com/web/fundamentals/architecture/app-shell
const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$');
registerRoute(
  // Return false to exempt requests from being fulfilled by index.html.
  ({ request, url }) => {
    // If this isn't a navigation, skip.
    if (request.mode !== 'navigate') {
      return false;
    } // If this is a URL that starts with /_, skip.

    if (url.pathname.startsWith('/_')) {
      return false;
    } // If this looks like a URL for a resource, because it contains // a file extension, skip.

    if (url.pathname.match(fileExtensionRegexp)) {
      return false;
    } // Return true to signal that we want to use the handler.

    return true;
  },
  createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html')
);

// An example runtime caching route for requests that aren't handled by the
// precache, in this case same-origin .png requests like those from in public/
registerRoute(
  // Add in any other file extensions or routing criteria as needed.
  ({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'), // Customize this strategy as needed, e.g., by changing to CacheFirst.
  new StaleWhileRevalidate({
    cacheName: 'images',
    plugins: [
      // Ensure that once this runtime cache reaches a maximum size the
      // least-recently used images are removed.
      new ExpirationPlugin({ maxEntries: 50 }),
    ],
  })
);

// This allows the web app to trigger skipWaiting via
// registration.waiting.postMessage({type: 'SKIP_WAITING'})
self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SKIP_WAITING') {
    self.skipWaiting();
  }
});

// Any other custom service worker logic can go here.

하지만 매번 작성하기는 번거롭기 떄문에 위 소스코드를 통해서 이미지를 모두 지정이 가능합니다.

 

 

src - index.js

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/serviceWorker.js')
      .then(registration => {
        console.log('Service Worker registered with scope:', registration.scope);
      })
      .catch(error => {
        console.log('Service Worker registration failed:', error);
      });
  });
}

다음으로 src - index.js를 수정해주어야 합니다.

 

index.js 내부에 해당 코드를 추가하여 앞서 생성한 service-worker.js를 등록합니다.

 

 

 

 

3. 공통 수정 부분

public - manifest.json 작성이 필요합니다.

 

manifest.json 파일은 React 생성 시 기본적으로 생성되는 파일입니다.

 

그 중에서 설치 화면 앱 이름 등에서 사용하는 short_name, name, favicon, logo 등을 수정해주어야 합니다.

 

short_name은 모바일 앱 이름으로, name은 설치 시 및 PC 화면에서 출력됩니다.

 

 

https://angelplayer.tistory.com/124

 

[HTML] 파비콘(주소창 아이콘) 적용 방법

웹 페이지에서 주소창 위에 나타나는 아이콘을 파비콘(Favicon)이라고 부릅니다. (즐겨찾기 등에서도 파비콘으로 지정한 아이콘이 나타납니다.) 오늘은 홈페이지 제작 시 파비콘을 적용하는 방법

angelplayer.tistory.com

favicon 생성 및 적용 방법은 위 포스트를 참고해주세요.

 

 

 

위 방법을 모두 적용하면 모바일 및 PC에서 React 앱을 설치 할 수 있으며, manifest.json에 적용한 이름이 적용된 것을 확인할 수 있습니다.

 

 

 

 

 

공유하기

facebook twitter kakaoTalk kakaostory naver band