본문 바로가기
카테고리 없음

09 프로그레시브 웹앱

by 살길바라냐 2021. 2. 11.
반응형

실시간 멀티 접속 테스트 

 

파이이베이스 db와 연결하기 위해
파이어베이스 sdk와 뷰파이어 플러그인 패키지 설치

npm install firebase vuefire@next 

@next 의미는 v2.0이상 의미함

 

Vue-CLI 사용하는 워크박스 : 
index.html, *css, *js, *txt를 자동으로 캐시함

- 플러그인 모드 :
GenerateSW (자동으로 생성되는 서비스 워커에 워크박스 옵션 지정)
InjectManifest (서비스 워커에 자신의 코드를 직접 넣어 최종 서비스 워커 파일 생성)

-캐시 :
프리 캐시 (실행하기 전에 미리 지정)

런타임 캐시 (프로그램 실행할때 원하는 부분만 지정)
--캐시전략
(Network-First, Cache-First, Stale-while-revalidate, Network-Only, Cache-Only) 

 

// generateSW 모드
module.exports = {
    pwa: {// 생략가능
        workboxPluginMode: 'GenerateSW',
        workboxOptions: {
            // 프리캐시 옵션 지정
            runtimeCaching: [{
                // 런타임 캐시 옵션 지정
            }]
        }
    }
}

// injectManifest 모드
module.exports = {
    pwa: {// 생략가능 불가능 반드시 지정
        workboxPluginMode: 'InjectManifest',
        workboxOptions: {
            // 서비스 워커 파일을 꼭지정
          swSrc: 'src/serviceworker.js',
        }
    }
}
module.exports = {
    pwa: {
        workboxOptions: {
          include: [/^index\.html$/, /\.css$/, /\.js$/, /^manifest\.json$/, /\.png$/],
          exclude:[]
        }
    }
}

include: 프리캐시에서 사용할 파일을 지정

exclude: 프리캐시에서 제거할 파일을 지정
제거할것이 없어도 반드시 명시해야한다. 

규칙은 테스트 모드로

<template>
  <v-app>
   <!-- 전체 영역을 카드ui로 변경하여 색상의 일관성을 유지 -->
   <v-card>
     <v-app-bar dark color="lime">
       <v-app-bar-nav-icon></v-app-bar-nav-icon>
       <v-toolbar-title>To-Do 리스트</v-toolbar-title>
     </v-app-bar>
     <v-content>
       <v-container>
         <v-row my-5>
           <v-col cols="8" offset="1">
             <!-- 실행되자마자 입력 포커스를 가지도록 autofocus 설정 -->
             <v-text-field label="할 일" autofocus v-model="sTodoTitle">
             </v-text-field>
           </v-col>
           <v-col cols="2" my-2>
             <v-btn 
             fab 
             max-height="50px" 
             max-width="50px" 
             color="pink"
             dark
             @click="fnSubmitTodo()"
             >
             <v-icon>add</v-icon>
             </v-btn>
           </v-col>
         </v-row>
         <v-row>
           <v-col cols="12">
             <v-list two-line v-for="item in oTodos" :key="item.key">
               <!-- item.b_edit 값을 통해 읽기 모드인 경우만 표시 -->
               <v-card flat color="grey lighten-3" v-if="!item.b_edit">
                 <!-- 항목을 하나씩 가져와서 title 단위로 표시 -->
                 <v-list-item class="py-2">
                   <v-list-item-action>
                     <!-- 체크박스 표시하고 선택되면 변경 상태를 DB에 저장 -->
                     <v-checkbox
                      v-model="item.b_completed"
                      @change="fnCheckboxChange(item)"
                     ></v-checkbox>
                   </v-list-item-action>
                   <!-- 제목 표시 체크선택시 취소선 표시 -->
                   <v-list-item-content>
                     <v-list-item-title :class="{'style_completed': item.b_completed}">
                       {{ item.todo_title }}
                     </v-list-item-title>
                      <!-- 두번째 줄에 아이콘 배치 -->
                      <v-list-item-subtitle class="mt-2">
                        <!-- 수정 아이콘 표시하고 클릭하면 수정모드로 변경함 -->
                        <v-icon class="pointer" @click="fnSetEditTodo(item['.key'])">create</v-icon>
                        <!-- 삭제 아이콘 표시하고 클릭하면 해당 item 삭제 -->
                        <v-icon class="pointer" @click="fnRemoveTodo(item['.key'])">delete</v-icon>
                            </v-list-item-subtitle>
                    </v-list-item-content>
                  </v-list-item>
                </v-card>
                   <!-- item.b_edit값을 통해 수정모드인 경우 어둡게 표시 -->
                <v-card v-else dark>
                  <v-list-item class="py-2">
                    <v-list-item-action>
                      <v-checkbox v-model="item.b_completed"></v-checkbox>
                    </v-list-item-action>
                    <!-- v-list-item안에서 텍스트입력과 버튼 사용을 위해  
										v-card 엘리먼트 사용 -->
                    <v-card-text>
                      <!-- 포커스를 입력창으로 바로 옮기고 삭제 아이콘도 추가함 -->
                      <v-text-field autofocus clearable v-model="item.todo_title"></v-text-field>
                    </v-card-text>
                    <v-card-actions>
                      <!-- 수정모드에서 '저장' 아이콘 클릭하면 해당 item 저장 -->
                      <v-icon class="pointer" @click="fnSaveEdit(item)">save</v-icon>
                      <!-- 수정모드에서 '취소' 아이콘 클릭하면 취소하고 읽기모드로
										 돌아감 -->
                      <v-icon class="pointer" @click="fnCancelEdit(item['.key'])">cancel</v-icon>
                    </v-card-actions>
                  </v-list-item>
                </v-card>
              </v-list>
            </v-col>
          </v-row>
        </v-container>
      </v-content>
    </v-card>
  </v-app>
</template>

<script>
  // 파이어베이스 DB 가져옴
  import {
    oTodosinDB
  } from '@/datasources/firebase'
export default {
  name: 'App',
  data: () => ({
      oTodos: [], // 할일 데이터 목록 저장 변수
      sTodoTitle: '' // 할 일 제목 저장 문자열 변수
  }),
   // 파이어베이스를 쉽게 사용하도록 oTodos 변수로 변경
    firebase: {
      oTodos: oTodosinDB
    },
    methods: {
      // 할 일 제목, 완료, 수정모드 상태값을 DB에 저장 
      fnSubmitTodo() {
        oTodosinDB.push({
          todo_title: this.sTodoTitle,
          b_completed: false,
          b_edit: false
        })
        this.sTodoTitle = ''
      },
      // 전달된 할 일을 DB에서 제거
      fnRemoveTodo(pKey) {
        oTodosinDB.child(pKey).remove()
      },
      // 전달된 할 일의 b_edit를 수정모드로 변경
      fnSetEditTodo(pKey) {
        oTodosinDB.child(pKey).update({
          b_edit: true
        })
      },
      // 전달된 할 일의 b_edit를 읽기모드로 변경
      fnCancelEdit(pKey) {
        oTodosinDB.child(pKey).update({
          b_edit: false
        })
      },
      // 전달된 할 일의 수정값을 DB에 저장
      fnSaveEdit(pItem) {
        const sKey = pItem['.key']
        oTodosinDB.child(sKey).set({
          todo_title: pItem.todo_title,
          b_completed: pItem.b_completed,
          b_edit: false
        })
      },
      // 첵크박스 선택되면 DB에 b_completed 변경값 저장
      fnCheckboxChange(pItem) {
        const sKey = pItem['.key']
        oTodosinDB.child(sKey).update({
          b_completed: pItem.b_completed
        })
      }
    }
};
</script>
<style>
  .pointer {
    /* 마우스포인터를 손모양으로 변경 */
    cursor: pointer;
  }

  .style_completed {
    /* 할 일의 제목을 취소선으로 변경 */
    text-decoration: line-through;
  }
</style>

   <v-list-item-title :class="{'style_completed': item.b_completed}">

클래스 바인딩 :  현재 엘리먼트에 적용된 클래스가 선택자를 사용될지를 
바인딩으로 결정하는 방법

item['.key']: 파이어베이스 고유키

class="pointer": 마우스가 근처에가면 손가락 모양으로 변경

@: src 폴더를 의미함

set(): 하위노드들에게도 업데이트 영향을 주게됨

 

 

module.exports = {
    pwa: {
        workboxOptions: {
            runtimeCaching: [{
                    urlPattern: /\.png$/,
                    handler: 'cacheFirst',
                    options: {
                        cacheName: 'png-cache',
                        expiration: {
                            maxEntries: 10, // 총 파일 10개까지 캐시
                            maxAgeSeconds: 60 * 60 * 24 * 365, // 1년 캐시 
                        }
                    }
                },
                {
                    urlPattern: /\.json$/,
                    handler: 'staleWhileRevalidate',
                    options: {
                        cacheName: 'json-cache',
                        cacheableResponse: {
                            statuses: [200]
                        }
                    },
                }
            ],
        }
    },
    devServer: {
        disableHostCheck: true
    }
}

handler: 5가지 캐시 전략 중 하나선택

urlPattern: 정규식 사요해서 캐시하려는 파일 또는 url 경로 지정

Options
-cahceName: 개발자 도구에 표시할 캐시 제목(중복 주의)
-expiration: 캐시제약 지정(maxEntries: 캐시할 개수, maxAgeSeconds: 캐시가 유지될 총 시간)
-cacheableResponse: HTTP 응답 코드를 통해 캐시 여부 결정

 

export default {
  aPictures: [{
    'id': 1,
    'url': 'https://farm1.staticflickr.com/654/22663129542_e3df218c90_b.jpg',
    'title': '청춘플랫폼_우수부스투표',
    'info': '졸업작품 전시회에 출품한 작품 중에서 방문자들이 직접 우수 전시 부스를 투표로 선정하는 모습입니다.'
  },
  {
    'id': 2,
    'url': 'https://farm1.staticflickr.com/739/22663128752_7b347e01a9_b.jpg',
    'title': '전시장모습',
    'info': '전시가 열렸던 예술의 전당 전시실 안의 모습입니다. '
  },
  {
    'id': 3,
    'url': 'https://farm1.staticflickr.com/674/22055529403_aeeb5fc371_b.jpg',
    'title': 'pc실습실',
    'info': '윈도우OS 환경에서 다양한 멀티미디어디자인 S/W를 실습하는 공간입니다.'
  },
  {
    'id': 4,
    'url': 'https://farm1.staticflickr.com/706/22650669476_d8bf33c153_b.jpg',
    'title': '졸업작품전시회 주제',
    'info': '청춘 플랫폼이라는 주제로 젊은 열정이 펼쳐지는 무대가 마련되었습니다.'
  },
  {
    'id': 5,
    'url': 'https://farm1.staticflickr.com/677/22055530223_91e3f73227_b.jpg',
    'title': '명함디자인',
    'info': '자신의 미래 모습을 담은 명함을 직접 디자인하고 인쇄 제작하여 전시한 모습입니다.'
  },
  {
    'id': 6,
    'url': 'https://farm1.staticflickr.com/777/22650669326_e180cd84ca_b.jpg',
    'title': '전시_방명록',
    'info': '전시장을 방문한 관객들의 다양한 소감을 방명록의 기록으로 남겨졌습니다.'
  },
  {
    'id': 7,
    'url': 'https://farm1.staticflickr.com/759/22687855771_92dc8b3245_b.jpg',
    'title': '매킨토시 실습실',
    'info': '맥OS 환경에서 멀티미디어디자인 관련 S/W를 사용하여 작업하기 위한 맥 실습실입니다.'
  },
  {
    'id': 8,
    'url': 'https://farm6.staticflickr.com/5646/22053918354_ee031eae46_b.jpg',
    'title': '캘리그래피_디자인',
    'info': '학생들이 직접 디자인한 아날로그 정서의 캘리그래피 작품입니다.'
  },
  {
    'id': 9,
    'url': 'https://farm1.staticflickr.com/762/22687856291_963df9b90a_b.jpg',
    'title': '실습실복도',
    'info': '전공존에 따라 색상이 그룹으로 연결된 실습실 복도 모습입니다.'
  },
  {
    'id': 10,
    'url': 'https://farm1.staticflickr.com/766/22055529593_c162dc3143_b.jpg',
    'title': '인터뷰_촬영',
    'info': '졸업작품을 준비한 학생들의 과정을 인터뷰의 기록으로 남기는 모습입니다. '
  },
  {
    'id': 11,
    'url': 'https://farm6.staticflickr.com/5775/22053918014_f0e0873b7c_b.jpg',
    'title': '전시_메모',
    'info': '관객들이 전시를 보면서 느낀 점을 간단한 메모의 글로 남긴 흔적입니다.'
  },
  {
    'id': 12,
    'url': 'https://farm6.staticflickr.com/5672/22055530083_8f633d57f3_b.jpg',
    'title': '종이컵_캘리그래피',
    'info': '종이컵을 캔버스 삼아 학생들의 자유로운 생각을 캘리그래피의 작품으로 제작한 종이컵 아트워크입니다.'
  }
  ]
}

 

ngrok.com/

외부에서 로컬 주소로 모바일로 접속하는 방법 

728x90