PWA(Progressive Web App)는 웹으로 개발된 서비스를 네이티브 앱과 같이 오프라인 작동, 설치 및 홈 화면 추가, 푸시 알림 등을 사용할 수 있도록 만들어 줍니다.
또한 모바일 뿐만 아니라 PC에서도 설치가 가능합니다.
PWA에는 Vue, React 등을 사용한다면 쉽게 프로젝트에 적용할 수 있습니다.
이번에는 React를 통해 만들어진 프로젝트에 PWA를 적용해보도록 하겠습니다.
서비스에 PWA를 적용하는 가장 편한 방법은 프로젝트 생성 시 PWA 템플릿을 사용하는 방법입니다.
$ npx create-react-app 프로젝트명 –template cra-template-pwa
기존 React 프로젝트 생성 방식에 말미에 –template cra-template-pwa를 붙임으로써 PWA 기능을 내장하는 React 앱을 생성할 수 있습니다.
기존에 생성된 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를 등록합니다.
public - manifest.json 작성이 필요합니다.
manifest.json 파일은 React 생성 시 기본적으로 생성되는 파일입니다.
그 중에서 설치 화면 앱 이름 등에서 사용하는 short_name, name, favicon, logo 등을 수정해주어야 합니다.
short_name은 모바일 앱 이름으로, name은 설치 시 및 PC 화면에서 출력됩니다.
https://angelplayer.tistory.com/124
favicon 생성 및 적용 방법은 위 포스트를 참고해주세요.
위 방법을 모두 적용하면 모바일 및 PC에서 React 앱을 설치 할 수 있으며, manifest.json에 적용한 이름이 적용된 것을 확인할 수 있습니다.
[Next.js] Meta Data 및 Open Graph 적용하기 (Feat. Next 14) (0) | 2024.08.02 |
---|---|
[Next] Next.js에서 폰트(글꼴) 변경하기 (Feat. Google, Local) (0) | 2024.07.07 |
[React] 페이지 이동 시 스크롤 화면 최상단 이동하기 (2) | 2024.02.10 |
[React] react-router-dom v6 프로젝트에 적용하기 (1) | 2023.11.02 |