특정 사이트에서 원하는 데이터를 자동으로 수집할 수 있는 크롬 확장 프로그램을 구현해보았습니다.
이번 프로젝트를 진행하면서 Manifest V3의 구조와 파일 간 메시지 통신 방식을 이해할 수 있었고, 특히 return true의 역할을 직접 경험해볼 수 있었습니다.
Manifest V3에서는 각 파일이 명확한 역할을 가지고 있습니다.
각 파일은 서로 직접 접근할 수 없으며 메시지(Message) 를 통해 통신합니다.
먼저 검색 결과 페이지에서 동작을 실행할 버튼을 생성했습니다.

버튼을 생성한 뒤 Object.assign()으로 스타일을 한 번에 적용했습니다.
Object.assign(openButton.style, {
position: "fixed",
top: "20px",
right: "20px",
zIndex: "999999",
padding: "10px 16px",
borderRadius: "8px",
border: "none",
background: "#2563eb",
color: "white",
cursor: "pointer",
fontSize: "13px",
});
Object.assign(closeButton.style, {
position: "fixed",
top: "70px",
right: "20px",
zIndex: "999999",
padding: "10px 16px",
borderRadius: "8px",
border: "none",
background: "#dc2626",
color: "white",
cursor: "pointer",
fontSize: "13px",
});
document.body.appendChild(openButton);
document.body.appendChild(closeButton);
Object.assign()을 사용하면 여러 스타일 속성을 객체 형태로 한 번에 적용할 수 있어 관리하기 편합니다.
또한 position: fixed와 높은 z-index를 사용해 어떤 페이지에서도 버튼이 항상 화면 위에 표시되도록 구현했습니다.
버튼을 클릭하면 실제 작업은 background.js에서 처리하도록 구현했습니다.
const { newCount, totalCount, stop } =
await chrome.runtime.sendMessage({
type: "OPEN_JOBS",
jobs,
});
chrome.runtime.sendMessage()를 이용해 Background로 작업을 요청하고, await으로 작업이 완료될 때까지 기다린 뒤 결과를 받아옵니다.
Background에서는 메시지를 받아 필요한 작업을 수행합니다.
chrome.runtime.onMessage.addListener(
(message, sender, sendResponse) => {
// ...
}
);
이번 프로젝트에서는 메시지 처리 과정에서 chrome.storage.local과 popup도 함께 사용했습니다.
chrome.storage.local은 크롬 확장 프로그램 전용 저장소입니다.
웹에서 사용하는 localStorage와 비슷하지만, 확장 프로그램 환경에서 사용할 수 있도록 제공되는 API입니다.
주로 작업 상태나 설정값처럼 브라우저를 종료해도 유지되어야 하는 데이터를 저장할 때 사용합니다.
popup은 확장 프로그램 아이콘을 클릭했을 때 표시되는 작은 HTML 화면입니다.
현재 작업 상태를 보여주거나 간단한 설정 화면을 구현할 때 자주 사용됩니다.
이번 프로젝트에서 가장 오래 헤맸던 부분이 바로 이것이었습니다.
Chrome의 메시지 채널은 리스너 함수가 종료되는 순간 함께 닫힙니다.
chrome.runtime.onMessage.addListener(
(message, sender, sendResponse) => {
handleMessage(message).then(sendResponse);
return true;
}
);
handleMessage()처럼 비동기 작업이 끝난 뒤 sendResponse()를 호출하는 구조라면 return true가 반드시 필요합니다.
return true는 Chrome에게
"아직 응답이 끝나지 않았으니 메시지 채널을 유지해 주세요."
라고 알려주는 역할을 합니다.
만약 return true가 없다면 비동기 작업이 끝나기 전에 채널이 먼저 닫히게 되고 sendResponse()가 호출되더라도 응답은 무시됩니다.
문서에서는 간단하게 설명되어 있는 내용이지만 직접 경험해보니 Manifest V3의 비동기 메시지 통신에서 가장 중요한 부분 중 하나라는 것을 알게 되었습니다.