참고
- 크롬 확장 프로그램 사이드 패널 만들기 (React Chrome Extension Side Panel Example)
이전 글에 이어 버튼을 클릭할 경우, 다음과 같이 현재 페이지의 URL과 HTML을 출력해 보자.
manifest.json 수정
크롬 확장 프로그램이 특정 페이지에서 동작하도록 권한을 추가한다.
아래 옵션은 모든 URL에 접근이 가능하다는 뜻이 된다.
"host_permissions": ["<all_urls>"]
그리고 permissions에서 activeTab을 추가한다.
"permissions": ["storage", "scripting", "tabs", "sidePanel", "notifications", "activeTab"],
eslintrc 파일 추가
chrome API를 사용하기 위해 루트 폴더에 .eslintrc.js을 추가한다.
.eslintrc.js는 다음과 같다.
module.exports = {
env: {
browser: true, // 브라우저 환경에서 사용 가능한 전역 객체 (window, document 등) 허용
webextensions: true, // chrome을 global 객체로 설정
es2021: true, // ES2021 문법 지원
},
parserOptions: {
ecmaVersion: 12, // 최신 ECMAScript 기능 지원
sourceType: "module", // ES6 모듈 지원
ecmaFeatures: {
jsx: true, // JSX 문법 지원
},
},
};
크롬 확장 프로그램 개발 중 chrome API를 호출하는 경우, Strict Mode에 의해 문제가 발생할 수 있다.
따라서 index.js에서 React.StrictMode를 제거한다.
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
background.js 수정 + contentScript.js 추가
backgroud.js에서 contentScript.js를 실행하는 코드를 추가한다.
chrome.action.onClicked.addListener((tab) => {
if (tab.id) {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ["contentScript.js"],
});
}
});
public/contentScript.js는 다음과 같다.
(() => {
console.log("start content script!!");
const pageUrl = window.location.href;
const pageHtml = document.documentElement.outerHTML;
console.log("Page URL:", pageUrl);
console.log("Page HTML:", pageHtml);
// HTML과 URL을 백그라운드로 전달
chrome.runtime.sendMessage({
type: "PAGE_INFO",
url: pageUrl,
html: pageHtml,
});
})();
URL과 HTML 가져오기
이제 다음 함수를 이용해서 URL과 HTML을 다음과 같이 가져올 수 있다.
실제 실행 코드는 전체 코드의 App.js를 참고하자.
const getPageInfo = async () => {
return new Promise((resolve, reject) => {
// 현재 활성 탭 정보 가져오기
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs[0]?.id) {
// content script 실행
chrome.scripting.executeScript(
{
target: { tabId: tabs[0].id },
files: ["contentScript.js"],
},
() => {
console.log("Content script executed!");
}
);
}
});
// content script에서 메시지 수신
chrome.runtime.onMessage.addListener((message) => {
console.log("here", message);
if (message.type === "PAGE_INFO") {
console.log("Page URL:", message.url);
console.log("Page HTML:", message.html);
resolve({
url: message.url,
html: message.html,
});
}
});
});
};
참고로 확장 프로그램의 콘솔 로그는 확장 프로그램에서 마우스 오른쪽 버튼 → 검사 탭에서 확인할 수 있다.
전체 코드는 다음과 같다.
App.js
import React from "react";
// import "./App.css";
function App() {
const getPageInfo = async () => {
return new Promise((resolve, reject) => {
// 현재 활성 탭 정보 가져오기
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs[0]?.id) {
// content script 실행
chrome.scripting.executeScript(
{
target: { tabId: tabs[0].id },
files: ["contentScript.js"],
},
() => {
console.log("Content script executed!");
}
);
}
});
// content script에서 메시지 수신
chrome.runtime.onMessage.addListener((message) => {
if (message.type === "PAGE_INFO") {
resolve({
url: message.url,
html: message.html,
});
}
});
});
};
const handleButtonClick = async () => {
try {
const result = await getPageInfo();
console.log("Received URL:", result.url);
console.log("Received HTML:", result.html);
} catch (error) {
console.error("Error:", error);
}
};
return (
<div>
<div className="App">
<h1>Get Tab Info</h1>
<button onClick={handleButtonClick}>URL & HTML</button>
</div>
</div>
);
}
export default App;
index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
.eslintrc.js
module.exports = {
env: {
browser: true, // 브라우저 환경에서 사용 가능한 전역 객체 (window, document 등) 허용
webextensions: true, // chrome을 global 객체로 설정
es2021: true, // ES2021 문법 지원
},
parserOptions: {
ecmaVersion: 12, // 최신 ECMAScript 기능 지원
sourceType: "module", // ES6 모듈 지원
ecmaFeatures: {
jsx: true, // JSX 문법 지원
},
},
};
public/background.js
// 확장 프로그램 클릭 시, 사이드 패널 Open
chrome.sidePanel
.setPanelBehavior({ openPanelOnActionClick: true })
.catch((error) => console.error(error));
// 설치 시 알림 및 초기 설정
chrome.runtime.onInstalled.addListener(() => {
console.log("Extension installed.");
// 알림 생성
chrome.notifications.create(
"welcome-notification",
{
type: "basic",
iconUrl: "icon.png",
title: "Welcome!",
message: "Click the extension icon to open the side panel.",
},
() => {
if (chrome.runtime.lastError) {
console.error("Notification error:", chrome.runtime.lastError.message);
}
}
);
});
chrome.action.onClicked.addListener((tab) => {
if (tab.id) {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ["contentScript.js"],
});
}
});
public/contentScript.js
(() => {
console.log("start content script!!");
const pageUrl = window.location.href;
const pageHtml = document.documentElement.outerHTML;
console.log("Page URL:", pageUrl);
console.log("Page HTML:", pageHtml);
// HTML과 URL을 백그라운드로 전달
chrome.runtime.sendMessage({
type: "PAGE_INFO",
url: pageUrl,
html: pageHtml,
});
})();
public/manifest.json
{
"manifest_version": 3,
"name": "React Side Panel Extension",
"version": "1.0",
"description": "React app in Chrome Side Panel",
"permissions": ["storage", "scripting", "tabs", "sidePanel", "notifications", "activeTab"],
"host_permissions": ["<all_urls>"],
"action": {
"default_title": "Click to open panel"
},
"side_panel": {
"default_path": "index.html"
},
"background": {
"service_worker": "background.js"
},
"web_accessible_resources": [
{
"resources": [
"index.html",
"static/*"
],
"matches": [
"<all_urls>"
]
}
]
}
'개발 > React' 카테고리의 다른 글
리액트 - 크롬 확장 프로그램 사이드 패널 만들기 (React Chrome Extension Side Panel Example) (0) | 2025.01.06 |
---|---|
리액트 - Vercel로 리액트 프로젝트 배포하기 (0) | 2024.05.02 |
리액트 - Netlify 배포 에러 해결하기 (Netlify Build and Deploy Error) (0) | 2024.04.25 |
리액트 - Netlify로 배포된 프로젝트에 리액트 라우터 적용하기 (0) | 2024.04.25 |
리액트 - Netlify로 리액트 프로젝트 배포하기 (0) | 2024.04.25 |
댓글