March 4, 2024 ˑ 18min read
크롬, 파이어폭스, 엣지, 오페라와 같은 주요 브라우저는 브라우저의 기능을 확장하거나 수정할 수 있는 확장 프로그램을 지원합니다. 브라우저 확장 프로그램은 브라우저의 기능을 확장하고 사용자의 경험을 개인화하는 데 중요한 역할을 하고 있는데요. 제공하는 API를 사용하면 웹 페이지의 UI를 변경하거나, 브라우저 이벤트를 감지하여 필요한 동작을 수행하는 등 다양한 응용이 가능합니다. 이번 글에서는 확장 프로그램을 개발하기에 앞서 확장 프로그램에 필요한 파일 구성과 그 역할에 대해 알아보려고 합니다.
NoteW3C에서는 크로스 브라우저간 확장 프로그램 호환성을 위해 WebExtensions Community Group(WECG) 을 운영하고 있습니다. WECG은 단일 코드베이스로 여러 브라우저에서 실행 가능한 확장 프로그램을 개발할 수 있는 표준을 만드는 것을 목적으로 하는데요. 현재까지는 초안 단계의 문서 만 공개하였고 문서에 설명되어있 듯 아직까지 W3C 표준화 트랙에도 등록되어있지 않은 상태입니다.
MDN 에 따르면 파이어폭스 확장 프로그램은 대체로 크로미움 기반 브라우저의 Extension API와 호환된다고 설명하고 있습니다. WECG에서 공식적인 표준을 내놓기 전까지는 Chrome Extension API가 사실상의 표준으로 사용되는 것으로 보입니다. 하지만
browser.*
네임스페이스로 API를 제공하는 파이어폭스와 달리 크롬 브라우저는chrome.*
을 통해 API를 제공하고 있는가 하면, 제공하는 API에도 차이가 있는 만큼 완전하게 호환되지는 않는 것 같습니다.이러한 이유로, 아직까지 확장 프로그램 표준화는 진행되고 있는 것으로 보이며 개발시에 참고하면 좋을 것 같습니다.
해당 게시글은 크롬 확장 프로그램을 기준으로 작성되었습니다.
크롬 확장 프로그램은 크게 아래와 같은 파일로 구성됩니다. 각 파일은 고유한 역할과 그에 따른 라이프 사이클을 갖게됩니다.
그럼 각 파일에 대해 더 자세하게 알아보겠습니다.
manifest.json
은 확장 프로그램 패키지에서 유일하게 필수로 존재해야 하는 파일로, 항상 루트 디렉토리에 위치해야합니다.
확장 프로그램에 대한 이름, 버전, 권한을 명시하고, 백그라운드 스크립트, 컨텐츠 스크립트와 같이 확장 프로그램을 이루는 요소에 대한 페이지, 스크립트 파일의 경로를 지정합니다.
{
"manifest_version": 3,
"name": "크롬 확장 프로그램 이름",
"version": "1.0",
"description": "크롬 확장 프로그램 설명",
"permissions": ["storage", "activeTab"],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
},
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"js": ["content.js"]
}
]
}
Manifest V3(MV3)는 보안, 성능, 개인정보 보호 강화를 목적으로 Google에서 발표한 새로운 표준입니다.
간단하게 살펴보면 아래와 같은 차이가 있습니다.
기능 | manifest v2 | manifest v3 |
---|---|---|
백그라운드 스크립트 | 지속적인 background.js 실행 | service_worker 을 통한 이벤트 기반 실행 |
웹 요청 차단 (Adblock 같은 확장) | webRequestBlocking API | declarativeNetRequest API |
컨텐츠 스크립트 실행 방식 | chrome.tabs.executeScript() | chrome.scripting.executeScript() |
외부 호스트 요청 (CORS) | 제한 없음 | host_permissions 추가 필요 |
권한 설정 | permissions 에 모든 권한 포함 가능 | host_permissions 로 웹사이트 접근 권한을 분리 |
CSP(Content Security Policy) | 제한 없음 | eval() , document.write() 사용 불가 |
Promise 지원 | 일부 지원 (콜백 방식) | 대부분 API에서 Promise 지원 |
Important크롬 확장 프로그램은 현재 manifest v3만 지원하고 있습니다.
확장 프로그램은 백그라운드 스크립트를 통해 웹페이지의 생명주기와는 독립적으로 브라우저의 이벤트를 처리할 수 있습니다.
과거 MV2의 백그라운드 스크립트는 window 컨텍스트. 즉, 웹 페이지와 같은 컨텍스트에서 실행되었습니다. 그렇기 때문에 DOM
이나 window
객체에도 접근이 가능했었죠.
그리고 스크립트 실행 방식에 따라 종류가 두가지로 나뉘었습니다.
백그라운드 페이지의 경우 확장 프로그램이 로드되는 즉시 로드되고 비활성화 되거나 제거될때까지 계속 실행됩니다. 항상 메모리를 점유하는 구조로 리소스를 많이 사용한다는 단점이 있었습니다.
이벤트 페이지는 백그라운드 페이지의 단점을 최적화하기 위해 이벤트가 발생할 때만 로드되어 필요한 동작을 수행하고, 처리가 끝나면 언로드(unload)되도록 동작합니다.
manifest.json의 background.persistent
필드를 통해 어떤 방식으로 동작할지 설정할 수 있었습니다.
이후에 등장한 MV3에서는 MV2의 이벤트 페이지 방식을 따르면서 서비스 워커를 사용하도록 변경되었고, 서비스 워커 자체의 제한적인 실행 환경으로 인해 DOM
, window
객체에 접근하지 못하게 되었습니다.
크롬 확장 프로그램에서는 MV3밖에 사용할 수 없다보니 MV2에 대한 내용은 참고로 알고있으면 좋을 것 같습니다.
MV3에서 manifest.json에서 백그라운드 스크립트는 background.service_worker
키를 통해 설정할 수 있습니다.
{
"manifest_version": 3,
"name": "My Extension",
"version": "1.0",
"permissions": ["storage", "tabs", "alarms"],
"background": {
"service_worker": "background.js"
},
...
}
MV2에서는 background.scripts
, background.persistent
와 같은 옵션이 사용되었지만 더 이상 사용되지 않습니다.
백그라운드 스크립트에서는 브라우저 이벤트나, 다른 요소에서 보낸 메세지를 주로 핸들링하게 됩니다. 백그라운드 스크립트는 다른 요소들과 달리 확장 프로그램을 위해 제공되는 모든 브라우저 API에 접근할 수 있기 때문에 일종의 API 허브의 역할을 담당합니다.
크롬 브라우저는 chrome.*
네임스페이스를 통해 이러한 API를 제공합니다.
Note아래부터는 Chrome에서 제공하는 브라우저 API를
Chrome Extension API
로 표기하도록 하겠습니다.
아래는 확장 프로그램의 요소별로 접근 가능한 Chrome Extension API
를 정리한 테이블입니다.
Chrome Extension API | 백그라운드 스크립트 | 유저인터페이스(팝업, 툴바) | 컨텐츠 스크립트 |
---|---|---|---|
chrome.runtime | ✅ | ✅ | ✅ 제한적 (sendMessage 등만) |
chrome.storage | ✅ | ✅ | ✅ |
chrome.tabs | ✅ | ✅ | ❌ |
chrome.windows | ✅ | ✅ | ❌ |
chrome.alarms | ✅ | ❌ | ❌ |
chrome.notifications | ✅ | ✅ | ❌ |
chrome.contextMenus | ✅ | ❌ | ❌ |
chrome.declarativeNetRequest | ✅ | ❌ | ❌ |
chrome.cookies | ✅ | ❌ | ❌ |
chrome.scripting | ✅ | ✅ | ❌ |
사용 가능 여부를 따져보았을 떄, 아래 API들은 사실상 백그라운드 스크립트 전용으로 볼 수 있습니다.
chrome.alarms
— 확장 프로그램을 위한 타이머 APIchrome.contextMenus
— 우클릭 메뉴와 관련된 APIchrome.declarativeNetRequest
— 네트워크 인터셉트 APIchrome.cookies
— 쿠키 APIchrome.runtime.onInstalled
, onStartup
— 확장 프로그램 라이프사이클 관리 APIchrome.webNavigation
, chrome.management
— 브라우저 네비게이션, 관리 API그럼 백그라운드 스크립트의 사용법과 주의사항에 대해 살펴보겠습니다.
백그라운드 스크립트는 이벤트 리스너를 통해 브라우저 이벤트를 핸들링한다는 소개를 드렸는데요. 확장 프로그램이 설치되거나 업데이트되는 것도 일종의 이벤트기 때문에 해당하는 이벤트 핸들러를 등록하여 필요한 작업을 수행할 수 있습니다.
초기화 이벤트 핸들러는 chrome.runtime.onInstalled
API를 사용할 수 있습니다. 처음 설치되었을 때 수행해야 하는 작업 — 기본 설정을 초기화한다거나, 알람을 보여주거나, 설치 이벤트에 대한 로깅과 같은 작업 을 진행할 수 있습니다.
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === 'install') {
// 확장 프로그램이 처음 설치될 때 실행
console.log("확장 프로그램이 설치되었습니다. 기본 설정을 초기화합니다.");
// 필요한 초기화 작업 수행 - 초기상태 저장
chrome.storage.local.set({
darkMode: false,
showNotifications: true,
launchCount: 0
}, () => {
console.log("기본 설정 저장 완료!");
});
} else if (details.reason === 'update') {
// 확장 프로그램이 업데이트 되었을 떄 실행
console.log("확장 프로그램이 업데이트되었습니다.");
}
});
동일한 방식으로 확장 프로그램에서 핸들링이 필요한 이벤트가 있다면 해당하는 API를 통해 이벤트 리스너를 등록할 수 있습니다.
// 북마크가 생성되었을 때 실행
chrome.bookmarks.onCreated.addListener(() => {});
// 탭이 업데이트 되었을 때 실행
chrome.tabs.onUpdated.addListener(() => {});
백그라운드 스크립트는 다른 요소와 메세지를 통해 필요한 정보를 주고 받을 수 있습니다. 메세지를 보내는 요소에서는 chrome.runtime.sendMessage
API를 사용합니다.
// Callback 방식
chrome.runtime.sendMessage({ type: "FROM_CONTENT", text: "페이지에서 인사합니다!" }, (response) => {
console.log("백그라운드 응답:", response);
});
// Promise 방식
const response = await chrome.runtime.sendMessage({ type: "FROM_CONTENT", text: "페이지에서 인사합니다!" })
console.log("백그라운드 응답:", response);
백그라운드 스크립트에서는 chrome.runtime.onMessage
API를 통해 메세지 이벤트 리스너를 등록하고 콜백 함수의 인자를 통해 전달받은 sendResponse
함수를 통해 응답할 수 있습니다.
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log("Content Script 메시지:", message.text);
sendResponse({ reply: "메시지 잘 받았어, content script!" });
});
// 비동기로 sendResponse를 호출하는 경우 `return true;` 추가하기
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
console.log("Content Script 메시지:", message.text);
await someAsyncFn()
sendResponse({ reply: "메시지 잘 받았어, content script!" });
return true;
});
NoteMV3부터 대부분의 Chrome Extension API에서 Promise를 지원합니다.
message API도 마찬가지로 Promise를 지원하는데요. 다만, 주의해야할 점으로는
chrome.runtime.onMessage
내에서 비동기로sendMessage
를 호출하게 되는 경우return true;
를 통해 보낸측에서 연결을 유지하도록 처리해야합니다. (Chrome 메세징 시스템은 Promise의 완료 여부와 관계없이return true;
를 통해 연결을 유지하는지 판단한다고 합니다.)
만약 메세지를 통해 전달해야하는 내용이 연속적이라면 port
객체를 사용할 수 있습니다.
chrome.runtime.connect
API를 통해 연결을 생성하면 port
객체를 얻을 수 있습니다. 이후에는 port
객체를 통해 메세지를 주고 받을 수 있습니다.
const port = chrome.runtime.connect({ name: "popup-channel" });
port.postMessage({ message: "안녕, 백그라운드!" });
port.postMessage({ message: "여기는 팝업." });
port.postMessage({ message: "앞으로 잘 부탁해!" });
port.onMessage.addListener((msg) => {
console.log("백그라운드 응답:", msg.reply);
});
백그라운드 스크립트에서는 chrome.runtime.onConnect
API를 통해 연결에 대한 이벤트 리스너를 등록하고 인자로 전달받은 port
를 통해 메세지를 처리할 수 있습니다.
chrome.runtime.onConnect.addListener((port) => {
console.log("연결된 포트 이름:", port.name);
port.onMessage.addListener((msg) => {
if (msg.message) {
console.log("메시지 수신:", msg.message);
port.postMessage({ reply: "안녕, 팝업! 메세지 잘 받았어." });
}
});
});
백그라운드 스크립트는 이벤트 기반으로 동작하는 서비스 워커를 통해 실행되기 때문에 브라우저의 판단 — 탭 이동, 브라우저를 닫는 등 리소스를 최적화할 수 있는 경우 에 따라 유휴 상태로 전환될 수 있었습니다. 그렇기 때문에 서비스 워커에서 setTimeout
, setInterval
같은 Web API를 사용하게되면 서비스 워커가 유휴 상태가 되면 등록한 콜백이 실행되지 않는 상황이 발생할 수 있습니다.
대신 크롬 브라우저는 백그라운드 스크립트에서 타이머 동작을 구성할 수 있도록 chrome.alarms
API를 제공합니다. chrome.alarms
API는 Web API와 달리 브라우저 수준에서 알람을 관리하기 때문에, 백그라운드 스크립트가 유휴 상태가 되거나 브라우저가 재시작되더라도 알람을 유지할 수 있습니다. 간단한 처리가 필요한 경우 Web API를 사용할 수도 있겠지만 chrome.alarms
를 사용하는것이 권장됩니다.
// 이벤트 리스너 등록
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === "everyMinute") {
console.log("1분마다 실행되는 작업!");
}
});
// 알람 이벤트 생성
chrome.alarms.create("everyMinute", {
periodInMinutes: 1
});
chrome.alarms
API에 대한 자세한 정보는 크롬 개발자 문서 를 참고해주세요.
이번 글에서는 크롬 확장프로그램의 구성과 백그라운드 스크립트에 대해 간단하게 알아보았습니다. 다음 글에서는 유저 인터페이스를 통해 사용자와 상호작용할 수 있는 확장 프로그램 요소들에 대해 알아보도록 하겠습니다. 감사합니다! :D
Chrome Extension
May 4, 2024
15 min read
Chrome, Firefox, Edge, Opera 등 주요 브라우저는 기능을 확장하거나 수정할 수 있는 확장 프로그램을 개발할 수 있는 환경과 API를 제공합니다. 확장 프로그램은 웹페이지의 UI를 변경하거나, 브라우저 이벤트를 감지하여 필요한 동작을 수행하는 등 다양한 응용이 가능한데요. 이번 글에서는 크롬 브라우저의 확장 프로그램을 개발하기에 앞서 확장 프로그램에 필요한 파일 구성과 그 역할에 대해 알아보려고 합니다.
Chrome Extension
May 4, 2024
12 min read
'React.js로 개발하는 크롬 확장 프로그램' 앞선 두 파트에서는 크롬 확장 프로그램을 구성하는 요소들에 대해 알아보았습니다. 이번 글에서는 Vite와 React.js를 이용하여 크롬 확장 프로그램 개발 환경을 구성하고, Chrome API를 사용하는 간단한 확장 프로그램을 만들어보겠습니다.