💂‍
Vue.js로 크롬 확장 프로그램을 만들어보자!

크롬 확장 프로그램 『전역일 계산기』를 기획하고 개발한 후 배포하는 과정을 소개합니다.

Posted by 재그지그 on July 21, 2019

Vue FrontEnd


술 한잔 마셨습니다… 앱이 잘 안되도 좋습니다. 하지만 『전역일 계산기』 하나만 기억해주세요. 진심을 다해 전합니다. 앱이 별로 일수있습니다. 밤낮으로 고민하고 개발 했습니다 …최선을 다했고 열심히 했습니다. 저의 진심이 느껴지길 바랍니다. 고맙습니다..

GIF

최근에 전역일 계산기라는 크롬 확장 프로그램을 하나 만들었습니다. 우연한 기회로 시작하게 된 토이 프로젝트였는데, 어느덧 크롬 웹 스토어에 배포까지 하게 되었습니다.

프론트엔드 개발을 시작한 지는 1년을 넘겼지만, 저 혼자서 프로그램을 기획하고 배포까지 해 본 건 처음이라 특별한 경험이었습니다. 물론 그 과정에서 헤매기도 많이 헤매었구요. 특히 크롬 확장 프로그램과 관련된 한글 자료들이 많이 없어서 고생을 좀 했습니다.

그래서 이번 포스트에서는 크롬 확장 프로그램을 개발하게 된 스토리에 대해 소개하고자 합니다. 이번 포스트를 통해, 크롬 확장 프로그램을 만들고 싶은 분이나 자기만의 웹 어플리케이션을 배포해보고 싶은 분들에게 도움이 되었으면 좋겠습니다.

사실 현재까지 개발한 기능이 많지는 않습니다. 우선은 필수적인 기능만 개발하여 배포했는데, 추가적인 기능은 꾸준히 업데이트 할 예정입니다.

만들게 된 동기

저는 지금 IT 산업기능요원으로 군 복무 중입니다. 대부분의 복무 중인 현역/보충역 분들이 그러하듯이, 저 역시 언제 전역/소집해제 하느냐! 가 주요 관심사였습니다.

image 구글 플레이에서 전역일로 검색하면 나오는 다양한 앱들. 사진에 나온 앱들은 모자이크 처리했습니다.

특히 스마트폰(구글 플레이)에서 둘러보면 다양한 전역일 계산기 앱들이 있죠. 저도 이 중에 여러 개를 써봤는데, 100% 만족할 만한 앱들은 찾기가 힘들더라구요.

  • 전역일 계산기 앱에 굳이 커뮤니티 기능이 필요한가?
  • 속도가 너무 느리다.
  • 앱이 너무 못 생겨서 쓰기 싫다(…)

그러다가 번뜩 든 생각이 이 정도 기능이라면 나도 하나 만들 수 있겠다였습니다. 그래서 조금 구체적으로 개발할 플랫폼을 찾아보다가, 크롬 확장 프로그램을 발견했습니다.

제가 여태까지 프론트엔드 개발을 해 왔고, 제 수준에서 충분히 구현 가능한 프로젝트이였기 때문이죠.

사전 조사

하지만 크롬 확장 프로그램에 대한 지식이 전혀 없었기 때문에, 사전 조사가 필요했습니다.

어떤 기술 스택을 이용해서 구현할 것인가?

그냥 바닐라 JavaScript를 쓸 수도 있지만 까다로운 DOM 처리와 상태 관리 시스템이 필요할 것 같아 SPA 프레임워크, 그 중에서도 가장 자신있는 Vue를 사용하기로 했습니다.

만들고 싶은 앱은 어떤 기능이 필요한가?

  1. 팝업형
  2. 부가 기능없이 최대한 심플하게
  3. 부담없이 사용할 수 있는 디자인
  4. 탭창에서 퍼센테이지 정보를 아이콘으로 빠르게 확인
  5. 날짜 퍼센트, 남은 날짜 확인, 복무 단축일 계산 기능
  6. 주 타겟은 컴퓨터를 사용할 수 있는 복무 중인 사람(ex: 사회복무요원, 전문연구요원, 산업기능요원)

크롬 확장 프로그램 중에서 이미 같은 용도의 프로그램이 이미 있는가?

크롬 웹 스토어에서 전역일로 검색을 하니 뭔가 다른 게 있었는데, 다행히 새 탭 테마에서 작동하는 확장 프로그램이라 분야가 겹치지는 않았습니다.

다른 전역일 계산기 앱들을 어떻게 조사할 건가?

다양한 스마트폰 어플리케이션을 직접 써보고, 필요한 부분을 정리하기로 했습니다.

디자인은 어떻게 할 건가?

UI 프레임워크, 그 중에서도 여태까지 안 써본 새로운 프레임워크를 써보기로 했습니다.

이렇게 어느 정도 “내가 무엇을 만들 것인가“에 대한 갈피를 잡은 후, 본격적으로 개발 환경 세팅에 들어갔습니다.

보일러 플레이트로 개발 환경 세팅하기

확장 프로그램 개발에 대한 사전 조사를 하던 중, Vue를 이용해 개발할 수 있는 보일러 플레이트를 여러 개 발견했습니다.

image

몇 개의 리포지토리 중에서도 가볍고, 사용법이 간단하면서도 꾸준히 관리되고 있는 것을 위주로 찾았습니다. 그래서 저는 이 보일러 플레이트를 사용하기로 했습니다.

그 후, 해당 리포지토리의 설명대로 설치를 진행했습니다.

vue init kocal/vue-web-extension military-service-calculator
cd military-service-calculator
npm install

이 보일러 플레이트는 웹팩 기반이라서, 아래와 같은 명령으로 개발용 서버를 실행시킬 수 있습니다.

npm run watch:dev

그리고 크롬을 열고, 확장 프로그램 페이지(chrome://extensions/)로 들어갑니다.

1

우측 상단에 있는 개발자 모드를 켜고, 압축해제된 확장 프로그램 로드 버튼을 클릭해서 /dist 디렉토리를 넣어줍니다. /dist는 빌드가 된 후 실행시킬 수 있는 결과물들이 들어있는 디렉토리입니다.

1

로드가 성공적으로 되면, 목록에 방금 추가한 확장 프로그램이 나옵니다. 여기에 있는 확장 프로그램 ID는 쓸 일이 많으니 따로 적어두시는 게 좋습니다.

1

그러면 크롬 주소창 우측에 있는 메뉴 바에 방금 설치한 확장 프로그램이 나옵니다. 이것을 클릭해보면, 우리가 만들 팝업 형태의 확장 프로그램이 뜹니다.

이 보일러 플레이트에서는 웹팩의 핫 리로드 기능을 이용해, 개발 서버를 이용하는 경우 파일을 수정하게 되면 작업하는 브라우저에서 바로 수정된 내용을 확인할 수 있다는 것도 큰 장점입니다.

보일러 플레이트 구조

보일러 플레이트를 이용해 서버를 켜고 확장 프로그램 로드까지 성공했다면, 현재 프로젝트의 구조에 대해 알아봅시다.

아래는 src 디렉토리의 구조로, vue-routervuex 등의 부가적인 디펜던시 설정에 따라 다를 수 있습니다. (사실 기억이 잘…)

├─icons
├─popup
├─router
├─store
└─views
    ├─components
    └─layout

그럼 /src/popup/app.vue에 있는 파일을 수정해, 변경된 내용이 확장 프로그램에 바로 적용이 되는지 확인해보겠습니다.


<template>
  <div id="app">
     {{ title }}
    <p>Hello world!</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      title: "title"
    };
  },
};
</script>

위와 같이 파일을 변경하고 저장하니, 아래와 같이 자동적으로 갱신된 결과물이 뜹니다.

1

지금 수정하고 있는 크롬 확장 프로그램은 크롬 브라우저 내에서 동작하는 chrome-extension://라는 특별한 프로토콜을 사용하는데,

chrome-extension://현재_크롬_확장_프로그램_아이디/popup/popup.html

이 주소를 직접 입력하면 마치 일반 웹 페이지에 접근하는 것처럼 새 창에서 확장 프로그램을 열 수 있습니다. 이 때 디렉토리 구조에 따라 경로는 조금씩 달라질 수 있습니다.

크롬 API와 퍼미션 리스트

위에서 보셨다시피 뷰(View)는 잘 나오고 있습니다. 이제는 데이터를 어떻게 저장해야 하는지에 대해 알아봅시다.

저도 잘 몰라서 검색해보았는데, 크롬 확장 프로그램에서 사용할 수 있는 다양한 크롬 API가 있고, 이것을 사용하기 위해서는 사용할 퍼미션 리스트manifest.json 파일에 작성해야 한다는 것을 발견했습니다.

그 중에서도 저는 전역일과 관련된 데이터를 로컬 크롬 브라우저에 저장해야 하기 때문에, 저장과 관련된 API인 storage를 사용하기로 했습니다. 아래와 같이 manifest.json에 퍼미션 목록을 적어주면, storage API에 접근할 수가 있습니다.

// manifest.json
"permissions": [
  "storage"
],

그 와중에 데이터 패치(fetch)를 어느 단계에서 해야할지 고민하다가, Vue의 라이프 사이클 테스트를 간단히 해봤습니다.

export default {
  created() {
    alert('created');
  },

  mounted() {
    alert('mounted');
  },
}

결과적으로 팝업이 한 번 열리고 닫힐 때마다, create, mount, destroy 단계를 거치는 것을 확인할 수 있었습니다. 따라서 매 번 앱이 클릭되어서 열리게 되는 단계인 create 훅에서 데이터를 패치하기로 했습니다.

아래는 크롬 Storage API를 이용해 데이터를 저장하는 간단한 예시입니다. Save 버튼을 누르면 데이터를 저장하고, 새로고침하면 저장된 데이터 뒤에 슬래시(/)를 붙여 데이터 패치를 하는 과정을 gif로 담았습니다.


<template>
  <div id="app">
    <input v-model="data" type="text"/>
    <button @click="save">Save</button>
    <br>
    {{ data }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      data: ""
    };
  },

  created() {
    chrome.storage.sync.get(['key'], (result) => {
      console.log('Value currently is ' + result.key);
      this.data = result.key + "/";
    });
  },

  methods: {
    save() {
      chrome.storage.sync.set({key: this.data}, () => {
        console.log('Value is set to ' + this.data);
      });
    }
  }
};
</script>

1

혹시 컴퓨터를 껐다 켜면 데이터가 사라지는 게 아닐까 걱정을 했지만, 다행히 앱을 지우기 전까지는 계속 저장이 되는 것을 확인했습니다. 이제 데이터를 저장할 준비도 완료되었습니다.

UI 프레임워크

저는 빠른 시간 안에 예쁘고, 깔끔한 UI 작업을 위해서는 프레임워크를 쓰는 게 좋다고 생각합니다.

원래 제가 주로 썼던건 Bootstrap, iView였는데 이번에는 왠지 새로운 프레임워크를 써 보고 싶었습니다. 그러다가 Element UI라는 것을 발견했고, 이번 프로젝트의 메인 UI 프레임워크로 사용하기로 했습니다.

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

npm을 이용해 설치해주고, Vue를 임포트(import)하는 JavaScript 파일에서 함께 임포트 해줍니다. 자세한 사용 방법은 UI 프레임워크의 설치법을 참조했습니다.

1

이제 UI프레임워크도 잘 동작하니, 아래와 같이 보기 좋게 레이아웃을 잡아주었습니다.

1

사실 여기서부터는 이제 일반적인 Vue 웹 어플리케이션을 만들듯, 여러분들이 만들고 싶은 작업을 시작하면 됩니다!

소프트웨어 구조와 플로우

이제 여기서부터는 디테일한 내용보다는 전반적인 구조를 소개해드리도록 하겠습니다. 사실, 원래 위의 단락까지는 개발 도중에 스크린샷을 찍어가며 포스트를 썼었는데, 개발에 집중하느라 도중에 글을 안 썼고, 지금은 이미 프로그램을 완성시키고 나서 리뷰를 쓰고 있기 때문(…)입니다.

1

  1. Chrome Storage API로 저장된 데이터를 App.vue로 뿌림
  2. App.vue의 상태 관리를 위해 Vuex에 데이터를 저장
  3. Vuex에 데이터 저장이 끝나면 각 컴포넌트에 데이터를 뿌림
  4. 만약 컴포넌트에서 데이터를 업데이트할 경우 Chrome Storage API를 호출해서 저장, 이벤트 리스너를 통해 데이터가 바뀔 경우 1번과 5번을 자동 실행
  5. Background.js에서는 Chrome Storage API로 불러온 데이터로 날짜 계산 기능을 수행
  6. Background.js에서는 주기적으로 현재 퍼센테이지를 바탕으로 뱃지를 변경하는 Chrome Badge API 호출
  7. 컴포넌트에서 뱃지 업데이트가 필요한 경우 컴포넌트에서 Chrome Badge API 호출

Chrome Storage API

데이터를 크롬 브라우저에 JSON 타입으로 저장하고 불러오는 역할을 합니다. 이 API는 위에서 이야기했듯, manifest.json 내부에 "permissions": ["storage"] 라고 퍼미션을 작성해주어야만 사용할 수 있습니다.

chrome.storage.sync.get(null, (result) => {})
chrome.storage.sync.set(null, (result) => {})

코드 내에서는 위와 같은 방법으로 호출할 수 있습니다. 첫 번째 파라미터에는 저장하거나 불러올 데이터를 적어줍니다. 이 API는 비동기 작업을 필요로 하기 때문에, 두 번째 파라미터에는 저장 또는 불러오기에 성공했을 때 실행할 콜백 함수를 적어주어야 합니다.

Chrome Badge API

크롬 주소창 우측의 크롬 메뉴에 뱃지를 띄우는 역할을 합니다. 이 API는 특별한 권한을 필요로 하지는 않습니다. text를 설정하면 지정한 값이 뜨고, 빈 스트링으로 하면 지워집니다. 최대 4글자까지 표현할 수 있습니다.

chrome.browserAction.setBadgeText({text: ""});

App.vue

UI와 함께 사용자 입력 부분을 담당하는 Vue 어플리케이션입니다. 일반적인 Vue 어플리케이션처럼, 라우터나 상태 관리 기능을 모두 사용할 수 있습니다.

Background.js

팝업형 확장 프로그램을 직접 클릭해서 켜지 않아도, 백그라운드에서 계속해서 돌아가는 자바스크립트 파일입니다. manifest.json에서 "background": {"scripts": ["background.js"]}라고 선언해주어야 사용할 수 있습니다.

배포하기

여태껏 만든 앱은 개발용이기 때문에 배포를 위해서는 아래와 같은 스크립트를 실행해주어야 합니다.

npm run build

그러면 dist/ 폴더의 내용이 배포에 적합한 상태가 됩니다. 이제 이 폴더를 .zip 확장자로 압축한 후, 크롬 웹 스토어에 등록하기만 하면 됩니다.

내가 만든 확장 프로그램을 배포하기 위해서는 우선 개발자 등록을 해야 합니다.

12

크롬 웹 스토어에 들어간 후, 우측 상단에서 개발자 대시보드를 클릭하면 됩니다. 최초로 개발자를 등록 하는 경우에는 5달러의 비용이 듭니다.

12

만약 성공적으로 개발자 등록을 했을 경우에는 뭔가 구려보이는 페이지가 뜰 텐데, 새로운 개발자 대시보드를 사용하는 링크로 이동하면 위와 같은 대시보드가 뜰 것입니다.

그 후, 새 항목 버튼을 누르고 아까 dist/ 디렉토리의 압축본을 잘 넣으면 됩니다.

14

그 후, 등록이 잘 되었으면 내가 만든 어플리케이션에 대한 자세한 정보와 함께 프로모션 이미지(캡쳐 화면)를 등록해야 합니다. 설명과 컨텐츠가 자세할수록, 사람들이 믿고 사용할 수 있겠죠? 그 후, 항목 게시 버튼을 누르면 곧 여러분이 만든 확장 프로그램이 웹 스토어에 배포됩니다!

마무리

앱을 배포하고 난 후 생활코딩 커뮤니티에 홍보한 덕분에 사용해주시는 분들도 꽤 늘었습니다. 실 사용자가 조금씩 늘어나다보니 뭔가 책임감 같은 것도 느껴지구요. 앞으로는 사용자를 좀 더 늘리기 위해 랜딩 페이지를 하나 만들어 볼 계획입니다.

14 풀 리퀘스트 보내주신 분도 계셨습니다! 감사해요!

덕분에 v1.0.0처럼, 버전 관리(versioning)를 어떻게 해야 잘 할 수 있는지라던가, 브랜치 전략을 어떻게 짜야하는지와 같은 소프트웨어의 배포에 관해서도 공부를 하게 되었습니다. 이 분야는 뭔가 하면 할 수록 배울 게 더 많아지는 분야라는 걸 새삼 깨닫습니다.

지금까지 전역일 계산기를 기획하고 만들고 배포하는 과정에 대해 적어보았습니다. 사실 만드는 모든 과정을 설명으로 적기에는 글 내용이 너무 장황해질 것 같아서, 실제 구현과 관련된 부분이 적지 않게 생략되었습니다. 혹시라도 이해하기 어렵거나 궁금한 부분이 있다면 댓글로 남겨주시길 부탁드리겠습니다.