ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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

    댓글

Designed by Tistory.