리액트로 만든 페이지 Progressive Web App 으로 만들기

신동규
17 min readFeb 12, 2020

Progressive Web App(PWA)?

Reliable — Service workers(pre-cache key resources 를 가능하게 해주는 client-side 프록시)는 네트워크의 상태에 상관없이 유저에게 즉각적이고 안정적인 화면을 제공해준다.

Fast — 53%정도의 유저들은 사이트에 들어갈때 3초 이상 페이지 로딩이 걸리게 되면 떠나간다고 합니다. 그리고 한 번 이상 로드되었다면 그 다음부터는 더 빠르게 페이지를 불러올 수 있어야 한다고 해요.

Engaging — PWA는 설치가 가능하여서 유저의 디바이스에 유지시킬 수 있습니다. 또한 홈스크린 아이콘을 변경할 수 있고, 처음에 뜨길 원하는 페이지를 설정할수도 있습니다.

Step 1: Set Up a Simple React App

create-react-app으로 리액트 간단한 어플리케이션을 준비해주세요!

npm install -g create-react-app
create-react-app pwa-task-manager
cd pwa-task-manager
npm install --save react-router-dom

src/App.js

import React, { Component } from 'react'; import { BrowserRouter, Route, Link } from 'react-router-dom'; import './App.css'; const NavBar = () => (
<div className="navbar">
<h3>Task Manager</h3>
<Link to="/">Current Tasks</Link>
<Link to="/completed">Completed Tasks</Link>
</div>
); const Template = (props) => (
<div>
<NavBar />
<p className="page-info">
{props.title}:
</p>
<ul className={props.status}>
<li>Task 1</li>
<li>Task 2</li>
<li>Task 3</li>
</ul>
</div>
); const CurrentTasks = () => (
<Template title="Current Tasks" status="Current" /> ); const CompletedTasks = () => (
<Template title="Completed Tasks" status="Completed" /> ); class App extends Component { render() { return (
<BrowserRouter>
<div>
<Route exact path="/" component={CurrentTasks}/>
<Route path="/completed" component={CompletedTasks}/>
</div>
</BrowserRouter>
); } } export default App;

스타일을 변경하고 싶으시다면 src/App.css 파일도 다음과 같이 작성해주세요.

.navbar {
background-color: #4169e1;
}
.navbar h3 {
display: inline-block;
text-align: left;
padding: 10px;
color: black;
text-decoration: none;
}
.navbar a {
display: inline-block;
padding: 10px;
color: #fff;
text-decoration: none;
}
.page-info {
padding: 10px;
}
.Current {
color: #2e8b57;
}
.Completed {
color: #ff6347;
text-decoration: line-through;
}

이제부터 본격적으로 PWA 로 웹페이지를 감싸봐요!

Step 2: Use the Audits Tab in Chrome Dev Tools

이번 단계에서는 우리는 크롬 개발자 도구에서 Audits 탭을 이용하도록 할겁니다. 해당 탭을 이용하면 우리의 웹페이지가 현재 PWA 로써 동작가능한지, 아닌지에 대해서 확인해주는 checklist를 제공해줍니다.

“Run audits”를 클릭하시면 Lighthouse(웹 페이지의 퀄리티 증진을 위한 자동화된 오픈소스 툴이에요) 가 보고서를 제출해줍니다.

제공된 보고서는 다음과같이 생겼어요.

자 그러면 불들을 끄러 가볼까요?

Step 3: Register a Service Worker

service worker란?

Service workers(pre-cache key resources 를 가능하게 해주는 client-side 프록시)는 네트워크의 상태에 상관없이 유저에게 즉각적이고 안정적인 화면을 제공해준다.

public/worker.js 파일을 생성해주시고 다음과 같이 작성해주세요:

var CACHE_NAME = 'pwa-task-manager';
var urlsToCache = [
'/',
'/completed'
];
// Install a service worker
self.addEventListener('install', event => {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
// Cache and return requests
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
})
);
});
// Update a service worker
self.addEventListener('activate', event => {
var cacheWhitelist = ['pwa-task-manager'];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});

Update your index.html file in the public folder (public/index.html) to check if the client’s browser supports service workers (lines 17–31):

클라이언트의 브라우저가 service workers 를 제공해주는지 확인하기 위해서public/index.html 파일도 이런식으로 수정해주세요. (lines 17–31):

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('worker.js').then(function(registration) {
console.log('Worker registration successful', registration.scope);
}, function(err) {
console.log('Worker registration failed', err);
}).catch(function(err) {
console.log(err);
});
});
} else {
console.log('Service Worker is not supported by browser.');
}
</script>
</body>
</html>

이제, src/index.js의 마지막줄에 있는 serviceWorker.unregister()를 serviceWorker.register()로 바꾸어줍니다

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render( < App / > , document.getElementById('root'));// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.register();

npm start 로 React app을 재시동시켜주세요. 그러면 콘솔창에서

Worker registration successful

이란 메시지를 확인하실 수 있으실 겁니다.

다시 크롬 개발자도구로 돌아가서 보고서를 실행시켜보세요. 다음과 같이 비슷하게 보일겁니다.

이제 여러분들의 웹페이지는:

  • 오프라인시에 response status 200으로 반응
  • service worker 을 등록

넘어갑시다!

Step 4: Apply the Principle of “Progressive Enhancement”

progressive enhancement?

Progressive enhancement 는 웹페이지의 주요 컨텐츠를 먼저 보여주고, 유저의 네트워크 커넥션에 따라서 불러올수 있는 컨텐츠들을 점진적으로 덧붙여서 유저에게 보여주는 전략입니다.

여러분의 리액트 어플리케이션을 자바스크립트의 로딩이 되기 전부터 화면에 보여줄수 있게 하기 위해서 13–45 라인과 50–57라인을 public/index.html 파일에 덧붙여주세요.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
<style type="text/css">
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}

.navbar {
background-color: #4169e1;
}

.navbar h3 {
display: inline-block;
text-align: left;
padding: 10px;
color: black;
text-decoration: none;
}

.navbar a {
display: inline-block;
padding: 10px;
color: #fff;
text-decoration: none;
}

.page-info {
padding: 10px;
}

.Current {
color: #2e8b57;
}

.Completed {
color: #ff6347;
text-decoration: line-through;
}
</style>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root">
<div class="navbar">
<h3>Task Manager</h3>
<a href="/">Current Tasks</a>
<a href="/completed">Completed Tasks</a>
</div>
<p class="page-info">
Loading...
</p>
</div>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('worker.js').then(function(registration) {
console.log('Worker registration successful', registration.scope);
}, function(err) {
console.log('Worker registration failed', err);
}).catch(function(err) {
console.log(err);
});
});
} else {
console.log('Service Worker is not supported by browser.');
}
</script>
</body>
</html>

Network 환경을 offline으로 바꾸고 여러분의 페이지를 리로딩해보세요. 위에 추가 작업한 내용들이 화면에 보여질것입니다.

Step 5: Add a Splash Icon

What are splash icons?

여러분들은 브라우저가 사용할 아이콘들을 설정해줄 수 있습니다. 이 아이콘들은 splash screen, task switcher, app launcher, home screen 등등에서도 사용되어질 수 있습니다.

audit을 통과하기 위해서는 512x512 pixel icon 이 하나 필요해요. Chrome은 자동적으로 아이콘을 기기종류에 따라 스케일링을 해줄거에요.

{
"short_name": "bible bot",
"name": "bible bot",
"icons": [ {
"src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon"
}
,
{
"src": "icon-256.png", "type": "image/png", "sizes": "256x256"
}
,
{
"src": "icon512.png", "type": "image/png", "sizes": "512x512"
}
],
"lang": "en-US",
"start_url": "/",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

저는 위와 같은 방식으로 해주었습니다.

앱을 재시작해주세요.

크롬 개발자 도구로 다시 돌아가서 audits을 확인해보세요. 아마 다음과 같이 보여지실 겁니다.

만약에 manifest 파일을 읽어들일수 없다라는 에러메시지가 나오게 된다면 강력 새로고침(맥에선 command + shift + f5)을 누르고 다시 확인해보세요. 이부분이 해결되지 않는다면 더이상 진행할 수 없으니 이부분을 꼭 넘겨주세요!

여기까지 성공하셨다면 이제 거의다 왔습니다!

Step 6: Deploy Your React PWA

마지막 단계는 http 트래픽을 https 로 바꿔주는 것입니다. 왜냐하면 여러분의 앱의 보안을 위해서입니다. 대부분의 경우에 모든 웹페이지들은 https 로 처리되어서 올라가지기 때문에 그렇게 큰 걸림돌이 될 것 같지는 않아요. 웹페이지를 https 로 감싸는 방법은 아주 쉽고 인터넷에 정보도 많기 때문에 이번 포스팅에선 다루지 않아요.

NOTE: 배포하시기 전에 지금까지의 진행상황들은 꼭 깃허브에 연동되어진 상태로 푸쉬가 되어져 있는 상태여야 하는것 명심해주세요.

특정한 개발 플랫폼(Firebase와 같은)에서 여러분의 앱은 자동으로 https 로 변경된 상태에서 업로드가 되어질 거에요. 만약에 다른 플랫폼을 사용하고 계신다면(Heroku, AWS, local pc) Cerificate Authority로 부터 증명서를 발급받아서 업로드 해주셔야 합니다.

Https 로 앱이 배포가 완료되어졌다면 여러분들의 앱은 PWA 설정이 모두 완료가 되어지셨을 겁니다!

Step 7: Download Your React PWA

만들었으니 이제 디바이스에서 다운받아봐야겠죠?

모바일에서 다운 받는 방법은 해당 페이지에 접속하셔서 홈 화면에 추가하기 버튼만 누르시면 된답니다.

--

--