-
PWA프론트엔드/React 2020. 8. 25. 01:41반응형SMALL
# What? 이게 뭔데
- Progressive Web Application
-> 웹에서도 앱처럼 static한 부분들을 설치 가능하게 해줌
-> 푸시알림 등 네이티브에서만 가능했던 부분들을 일부 웹에서도 가능하게 해줌
# Why? 이거 왜 써야 하는데?
- 사용자에게 더 나은 사용환경을 제공해주기 위해서
# How? 어떻게 쓰는데?
1. manifest.json 생성
@ public/manifest.json
{ "name" : "매일점심", "short_name": "매일점심", "display": "standalone", "background_color": "#fff", "theme_color": "#ff9711", "orientation": "portrait-primary", "icons" : [ { "src" : "/img/icon-192x192.png", "type" : "image/png", "sizes" : "72x72" }, { "src" : "/img/icon-192x192.png", "type" : "image/png", "sizes" : "96x96" }, { "src" : "/img/icon-192x192.png", "type" : "image/png", "sizes" : "144x144" }, { "src" : "/img/icon-192x192.png", "type" : "image/png", "sizes" : "152x152" }, { "src" : "/img/icon-192x192.png", "type" : "image/png", "sizes" : "192x192" }, { "src" : "/img/icon-192x192.png", "type" : "image/png", "sizes" : "384x384" }, { "src" : "/img/icon-192x192.png", "type" : "image/png", "sizes" : "512x512" } ] }
-> 원래 각 사이즈별 이미지 제작해야하는데 일단 귀찮아서 192x192 이미지로 돌려막음
2. index.html에 연결하기
@ index.html(나같은 경우엔 app.blade.php)
<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="scrollbar type01"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{config("app.name")}}</title> <meta name="csrf-token" content="{{ csrf_token() }}"> <meta name="theme-color" content="#ff9711"> <link rel="stylesheet" href="/css/default.css?{{\Illuminate\Support\Carbon::now()}}"> <link rel="stylesheet" href="/css/animate.css?{{\Illuminate\Support\Carbon::now()}}"> <link rel="stylesheet" href="/css/common.css?{{\Illuminate\Support\Carbon::now()}}"> <link rel="stylesheet" href="/css/style.css?{{\Illuminate\Support\Carbon::now()}}"> <script src="/js/kakao.js"></script> <link rel="manifest" href="/manifest.json"> <link rel="apple-touch-icon" href="/img/icon-192x192.png"> </head> <body> <div id="app"> </div> <script src="{{mix('/js/app.js')}}?{{\Carbon\Carbon::now()}}"></script> <script type="text/javascript" src="https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=ue3zysm2ng"></script> </body> </html>
<meta name="theme-color" content="#ff9711">
<link rel="manifest" href="/manifest.json">
<link rel="apple-touch-icon" href="/img/icon-192x192.png">3. fallback.html 생성
-> 인터넷 끊겼을 때 뜨게 할 화면
@ public/fallback.html
<!doctype html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>네트워크 오류</title> </head> <body style="background-color:#ff9711"> <div class="content" style="width:100%; position:absolute; top:45%; left:50%; transform:translate(-50%, -50%); text-align:center;"> <img src="./img/logo.png" alt="" style=""> <p class="text" style="font-size:18px; font-weight:500; color:#fff;"> 네트워크 연결에 문제가 있습니다. </p> </div> </body> </html>
4. public/sw.js 생성 후 app.js에서 호출
@ sw.js
const staticCacheName = 'site-static-v3'; const dynamicCacheName = 'static-dynamic-v3'; const assets = [ "/", "/js/app.js", "/js/kakao.js", "/css/animate.css", "/css/app.css", "/css/common.css", "/css/default.css", "/css/style.css", "/img/icon-192x192.png", "/img/logo.png", "/img/spoon.png", "/favicon.ico", "/fallback.html" ]; // 폰트도 은근 크니까 캐싱하길 추천 // install service worker self.addEventListener("install", event => { // console.log("service worker has been installed"); event.waitUntil( caches.open(staticCacheName).then(cache => { cache.addAll(assets); }) ); }); // activate service worker self.addEventListener("activate", event => { event.waitUntil( caches.keys().then(keys => { return Promise.all(keys .filter(key => key !== staticCacheName && key !== dynamicCacheName) .map(key => caches.delete(key))) }) ) }); // fetch event self.addEventListener("fetch", event => { // 등록해놨던 캐쉬 뿌리기(요청이 캐쉬해놨던 리소스랑 일치하면) event.respondWith( caches.match(event.request).then(cacheResponse => { return cacheResponse || fetch(event.request).then(fetchResponse => { return caches.open(dynamicCacheName).then(cache => { cache.put(event.request.url, fetchResponse.clone()); return fetchResponse; }) }); }).catch(() => caches.match("/fallback.html")) ) });
@ app.js
import store from './store'; import setUpInterceptor from './utilities/interceptors'; if('serviceWorker' in navigator){ navigator.serviceWorker.register("/sw.js", {scope: '.'}) .then((response) => console.log("service worker registered", response)) .catch((error) => console.log("service worker not registered", error)); } window.dataURLtoFile = (url, fileName) => { var arr = url.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], fileName, {type:mime}); }; /** * First we will load all of this project's JavaScript dependencies which * includes React and other helpers. It's a great starting point while * building robust, powerful web applications using React + Laravel. */ require('./bootstrap'); /** * Next, we will create a fresh React component instance and attach it to * the page. Then, you may begin adding components to this application * or customize the JavaScript scaffolding to fit your unique needs. */ require('./Index');
LIST'프론트엔드 > React' 카테고리의 다른 글
[작성중] 6-1. Custom Form Input 컴포넌트 만들기 (0) 2024.03.03 SWR (0) 2020.08.17 9. Auth (0) 2020.02.05 08. Redux(리덕스) (0) 2020.02.04 07. 리액트 라우터(React Router) (0) 2020.02.04