[크롬 익스텐션] - 아키텍처와 튜토리얼

🌈 크롬 익스텐션

크롬 익스텐션은 사용자가 원하는 기능을 추가로 설치하여 웹을 더욱 편하게 이용하게 해주는 프로그램입니다.

이번에 프로젝트로 크롬익스텐션을 만들게 되었는데 이에 대해 튜토리얼 및 자료들을 보면서 한국어로된 버전도 있으면 좋을것 같아 정리하게 되었습니다.

🏛 Architecture

크롬 익스텐션은 다음과 같은 구성 요소로 이루어집니다.

  • Manifest
  • Background Script
  • UI Elements
  • Content Script
  • Options Page

🪵 Manifest

모든 크롬 익스텐션은 중요한 정보를 제공하는 manifest.json이라는 JSON 형식의 파일을 가지고 있습니다.

json 파일에 많은 속성들을 넣을 수 있는데 이 부분은 튜토리얼을 진행하면서 같이 보겠습니다.

기본적인 manifest.json 예시

{
  "name": "My Extension",
  "description": "A nice little demo extension.",
  "version": "2.1",
  "manifest_version": 3,
}

🪵 Background script

백그라운드 스크립트는 익스텐션의 이벤트 핸들러이며 익스텐션에 중요한 브라우저 이벤트들의 리스너들을 포함합니다. 백그라운드에서 계속 돌아가면서 이벤트가 발생하면 지시된 논리를 수행합니다.

여기서 말하는 이벤트는 새 페이지로 이동, 책갈피 제거 또는 탭 닫기와 같은 브라우저 트리거를 말합니다.

백그라운드 스크립트를 등록하기 위해서는 manifest에 다음과 같은 설정을 해주어야 합니다.

{
  "name": "My Extension",
  "description": "A nice little demo extension.",
  "version": "2.1",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
}

🪵 UI Elements

익스텐션의 유저 인테페이스 부분을 담당합니다. 튜토리얼이나 아키텍처에서는 popup.html을 말하며 이 팝업 페이지에서 tabs.create 혹은 window.open() 을 호출하여 다른 페이지를 띄울수도 있습니다.

일반적으로 기본적인 팝업 설정은 manifest에서 다음과 같이 작성합니다.

{
  "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "popup.html",
  },
}

🪵 Content Script

웹 페이지를 읽거나 쓰는 확장 기능은 컨텐츠 스크립트를 사용합니다. 이 스크립트는 브라우저가 방문하는 웹 페이지의 DOM읽고 수정합니다.

컨텐츠 스크립트는 메시지를 교환하고 스토리지 API를 사용하여 값을 저장함으로써 상위 확장과 통신할 수 있습니다.

🪵 Options Page

익스텐션을 통해 크롬 브라우저를 커스터마이징 하는 것처럼 옵션 페이지도 익스텐션을 커스터마이징하게 만들어줍니다. 옵션을 사용하여 기능을 활성화하고 사용자가 원하는 기능들을 선택할 수 있게 만들어줍니다.

manifest에 다음과 같이 설정합니다.

{
  ...
  "options_page": "options.html"
}

여기까지가 크롬 익스텐션의 아키텍처이며 아래는 튜토리얼 내용과 React 프로젝트에서 어떤식으로 크롬 익스텐션을 만드는지에 대한 내용입니다.

크롬 익스텐션을 개발할 때, 크롬 API를 알면 더욱 효과적이고 브라우저와의 긴밀한 통합을 만들 수 있습니다.

참고사이트: API Reference

✏️ Tutorial

이 튜토리얼에서는 간단한 HTML/CSS를 활용하여 크롬 익스텐션의 버튼을 누르면 그 색으로 화면의 배경색이 변하는 앱을 만들어봅니다.

✔️ manifest.json 만들기

우선 작업할 공간에 manifest.json 파일을 만들어줍니다.

{
  "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 3
}

✔️ 크롬 확장 플러그인에 들어가서 확인

이후 크롬 브라우저의 확장 프로그램 관리에 들어가서 다음과 같이 누르면

현재 만들어진 확장 프로그램 등록이 가능합니다.

현재는 아무 기능이 없기 때문에 기능을 추가해 봅시다.

✔️ 백그라운드 스크립트 등록하기

{
  "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  }
}

백그라운드 스크립트를 등록하고, background.js라는 파일을 만들어 다음과 같이 작성해봅시다.

let color = '#3aa757';

chrome.runtime.onInstalled.addListener(() => {
  chrome.storage.sync.set({ color });
  console.log('Default background color set to %cgreen', `color: ${color}`);
});

안의 onInstalled는 확장을 처음 설치할 때, 새 버전으로 업데이트할 때, Chrome을 새 버전으로 업데이트할 때 실행됩니다.
또한 storage API를 사용하는데, 이는 LocalStorage API와 동일한 스토리지 기능을 제공하지만 약간의 차이점이 존재합니다.

차이점은 간단한게 아래와 같고 더 알고싶다면 아래의 링크를 참고해주세요

  • 사용자 데이터는 Chrome sync(storage.sync 사용)와 자동으로 동기화 될 수 있다.
  • localStorage API보다 빠르다.
  • 사용자 데이터를 객체로 저장할 수 있다.

링크: chrome.storage

✔️ 스토리지 permission 추가하기

스토리지 API를 포함한 대부분의 API는 manifest의 권한 필드에 등록되어있어야 사용 가능합니다.

{
  ...
  "permissions": ["storage"]
}

이후, reload를 한 뒤, 서비스 워커를 클릭하여 콘솔창을 보면 백그라운드 스크립트가 잘 작동되었다는 다음과 같은 화면을 볼 수 있습니다.

✔️ 유저 인터페이스 만들기

이제 익스텐션을 누르면 보일 인터페이스를 만들 차례입니다.

작업 폴더 아래에 popup.html을 만들고 다음과 같이 만들어봅시다.

popup.html

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="button.css">
  </head>
  <body>
    <button id="changeColor"></button>
  </body>
</html>

button.css

button {
  height: 30px;
  width: 30px;
  outline: none;
  margin: 10px;
  border: none;
  border-radius: 2px;
}

button.current {
  box-shadow: 0 0 0 2px white, 0 0 0 4px black;
}

이후 manifest에 추가를 해주어야 팝업창에 표시할 수 있는데, 그 전에 이미지 추가를 위해 아래 링크에서 이미지들을 다운 받고 작업환경에 images 라는 폴더를 추가해줍시다. 그 이후 manifest에 아이콘 등록도 해주면 됩니다.

이미지 폴더 링크

manifest.json

{
  "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "/images/get_started16.png",
      "32": "/images/get_started32.png",
      "48": "/images/get_started48.png",
      "128": "/images/get_started128.png"
    }
  },
  "icons": {
    "16": "/images/get_started16.png",
    "32": "/images/get_started32.png",
    "48": "/images/get_started48.png",
    "128": "/images/get_started128.png"
  }
}

여기서 default_icon은 도구모음 아이콘의 지정을 위한 것이며 icons는 확장 관리 페이지, 권한 경고 및 즐겨찾기 아이콘에도 이미지를 표시하기위해 적용한 것입니다.

이후 크롬 익스텐션을 고정시키고 보면 다음과 같은 화면을 확인할 수 있습니다.

위 버튼에 아까 백그라운드 스크립트에 저장해둔 색을 사용하려면 popup.js를 만들어 다음의 코드를 추가하면 됩니다

popup.js

let changeColor = document.getElementById('changeColor');

chrome.storage.sync.get('color', ({ color }) => {
  changeColor.style.backgroundColor = color;
});

이후 popup.html에도 추가해줍시다.

popup.html

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="button.css">
  </head>
  <body>
    <button id="changeColor"></button>
    <script src="popup.js"></script>
  </body>
</html>

이제 확장자의 버튼을 눌렀을 때, 그 색으로 화면의 색을 변경하기 위한 popup.js 코드를 업데이트 시켜주어야합니다.

popup.js

// 버튼을 클릭했을때, 현재 페이지에 설정된 배경색으로 바꿉니다.
changeColor.addEventListener("click", async () => {
  let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    function: setPageBackgroundColor,
  });
});

// 이 함수의 본문은 컨텐츠 스크립트로 실행됩니다.
// 현재 페이지
function setPageBackgroundColor() {
  chrome.storage.sync.get("color", ({ color }) => {
    document.body.style.backgroundColor = color;
  });
}

chrome.tabs.queryTab[]이라는 프로미스를 반환하며 지정된 속성이 있는 모든 탭을 가져오거나, 속성이 지정되지 않은 경우 모든 탭을 가져옵니다. active는 창이 활성화 되어있는지, currentWindow는 탭이 현재 창에 있는지를 물어보는 속성입니다.
chrome.scripting은 아래와 같은 형식으로 사용합니다.

이후 manifest에 현재 페이지에 대한 익스텐션 임시 액세스를 허용하는 activeTab 사용 권한과 스크립팅 API의 executeScript 메서드를 사용하는 스크립팅 권한이 필요합니다.

manifest.json

{
  ...
  "permissions": ["storage", "activeTab", "scripting"],
}

이후 크롬 익스텐션을 눌러보면

다음과 같이 완성된 모습을 볼 수 있습니다.

✔️ 유저에게 옵션주기

현재 익스텐션은 녹색으로만 변경할 수 있는데, 사용자가 익스텐션 기능을 더 많이 제어하도록 옵션을 줄 수 있습니다. 이를 위한 작업을 진행해 봅시다.

작업 폴더안에 options.html 파일을 만듭니다.

options.html

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="button.css">
  </head>
  <body>
    <div id="buttonDiv">
    </div>
    <div>
      <p>Choose a different background color!</p>
    </div>
  </body>
  <script src="options.js"></script>
</html>

이후 manifestoptions_page를 등록합니다.

{
  "name": "Getting Started Example",
  ...
  "options_page": "options.html"
}

익스텐션을 리로드한 뒤 익스텐션에 우클릭을 하면 다음과 같은 화면을 볼 수 있습니다.

마지막은 options.js를 만들어 로직을 추가하는 것입니다.

options.js

let page = document.getElementById("buttonDiv");
let selectedClassName = "current";
const presetButtonColors = ["#3aa757", "#e8453c", "#f9bb2d", "#4688f1"];

// 버튼 클릭에 반응하여 선택된 버튼을 마킹하고 저장합니다.
// 선택
function handleButtonClick(event) {
  // 전에 선택된 색상 버튼의 스타일링을 제거합니다.
  let current = event.target.parentElement.querySelector(
    `.${selectedClassName}`
  );
  if (current && current !== event.target) {
    current.classList.remove(selectedClassName);
  }

  // 선택한 버튼을 마킹합니다.
  let color = event.target.dataset.color;
  event.target.classList.add(selectedClassName);
  chrome.storage.sync.set({ color });
}

// 제공된 각 색상에 대해 페이지에 버튼을 추가합니다.
function constructOptions(buttonColors) {
  chrome.storage.sync.get("color", (data) => {
    let currentColor = data.color;

    for (let buttonColor of buttonColors) {
      let button = document.createElement("button");
      button.dataset.color = buttonColor;
      button.style.backgroundColor = buttonColor;

      if (buttonColor === currentColor) {
        button.classList.add(selectedClassName);
      }

      button.addEventListener("click", handleButtonClick);
      page.appendChild(button);
    }
  });
}

// 색상 옵션을 구성하여 페이지 초기화
constructOptions(presetButtonColors);

이후 옵션에 들어가면 색상을 선택할 수 있습니다.

전체 코드는 여기서 확인할 수 있습니다.

https://github.com/hustle-dev/Frontend-Skill/tree/main/chrome-extension-example

📚 참고사이트

좋은 웹페이지 즐겨찾기