본문 바로가기
개발/React

리액트 - 크롬 확장 프로그램에서 현재 페이지 변경하기 (Chrome Extension Script Injection)

by 피로물든딸기 2025. 2. 2.
반응형

리액트 전체 링크

 

참고

- 크롬 확장 프로그램 사이드 패널 만들기

- 크롬 확장 프로그램에서 현재 페이지의 URL과 HTML 가져오기

- 크롬 확장 프로그램에서 현재 페이지 변경하기

 

크롬 확장 프로그램에서 Highlight 버튼을 클릭하면, button a tag를 아래와 같이 바꾸도록 해보자.


highlight.js 추가

 

public/highlight.js에 아래 코드를 추가한다.

button a tag를 모두 찾아서 border 스타일을 변경하였다.

(() => {
  const hElements = document.querySelectorAll("button, a");
  hElements.forEach((el) => {
    el.style.border = "2px solid red";
  });
})();

App.js

 

App.js는 highlight 함수를 추가하고, highlight.js를 호출하면 된다.

  const highlight = () => {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      if (tabs[0]?.id) {
        chrome.scripting.executeScript(
          {
            target: { tabId: tabs[0].id },
            files: ["highlight.js"], // 새로 추가할 content script
          },
          () => {
            console.log("Highlight script executed!");
          }
        );
      }
    });
  };

 

그리고 버튼을 추가하여 onClick에 함수를 추가하면 된다.

      <p>
        <button onClick={highlight}>Highlight</button>
      </p>

 

전체 App.js는 다음과 같다.

import React from "react";

function App() {
  const getPageInfo = async () => {
    return new Promise((resolve, reject) => {
      chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
        if (tabs[0]?.id) {
          chrome.scripting.executeScript(
            {
              target: { tabId: tabs[0].id },
              files: ["contentScript.js"],
            },
            () => {
              console.log("Content script executed!");
            }
          );
        }
      });

      chrome.runtime.onMessage.addListener((message) => {
        if (message.type === "PAGE_INFO") {
          resolve({
            url: message.url,
            html: message.html,
          });
        }
      });
    });
  };

  const highlight = () => {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      if (tabs[0]?.id) {
        chrome.scripting.executeScript(
          {
            target: { tabId: tabs[0].id },
            files: ["highlight.js"], // 새로 추가할 content script
          },
          () => {
            console.log("Highlight script executed!");
          }
        );
      }
    });
  };

  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 className="App">
      <h1>Get Tab Info</h1>
      <p>
        <button onClick={handleButtonClick}>URL & HTML</button>
      </p>
      <p>
        <button onClick={highlight}>Highlight</button>
      </p>
    </div>
  );
}

export default App;

스크립트 대신 함수로 처리하기

 

만약 다른 태그의 스타일도 변경하려면, 스크립트 자체를 바꿔야하기 때문에 비효율적이다.

이런 경우, script를 넘기지 말고 함수를 넘기는 방법을 사용할 수 있다.

 

먼저 highlight 함수를 App.js 내에 선언한다.

  const highlightElementsScript = (targetTag) => {
    document.querySelectorAll(targetTag).forEach((el) => {
      el.style.border = "2px solid red";
    });
  };

 

injection할 코드는 함수가 되었으므로, files: ["highlight.js"]삭제하고 functionargs를 추가한다.

  const highlightFunc = (targetTag) => {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      if (tabs[0]?.id) {
        chrome.scripting.executeScript(
          {
            target: { tabId: tabs[0].id },
            function: highlightElementsScript, // content script 실행
            args: [targetTag], // 파라미터 전달 
          },
          () => {
            console.log("Highlight script executed!");
          }
        );
      }
    });
  };

 

buttononClick에 선언된 함수는 다음과 같이 수정하면 된다.

  const highlight = () => {
    highlightFunc("button");
    highlightFunc("a");  
  };

 

전체 코드는 다음과 같다.

import React from "react";

function App() {
  const getPageInfo = async () => {
    return new Promise((resolve, reject) => {
      chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
        if (tabs[0]?.id) {
          chrome.scripting.executeScript(
            {
              target: { tabId: tabs[0].id },
              files: ["contentScript.js"],
            },
            () => {
              console.log("Content script executed!");
            }
          );
        }
      });

      chrome.runtime.onMessage.addListener((message) => {
        if (message.type === "PAGE_INFO") {
          resolve({
            url: message.url,
            html: message.html,
          });
        }
      });
    });
  };



  const highlightElementsScript = (targetTag) => {
    document.querySelectorAll(targetTag).forEach((el) => {
      el.style.border = "2px solid red";
    });
  };

  const highlightFunc = (targetTag) => {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      if (tabs[0]?.id) {
        chrome.scripting.executeScript(
          {
            target: { tabId: tabs[0].id },
            function: highlightElementsScript, // content script 실행
            args: [targetTag], // 파라미터 전달 
          },
          () => {
            console.log("Highlight script executed!");
          }
        );
      }
    });
  };

  const highlight = () => {
    highlightFunc("button");
    highlightFunc("a");  
  };

  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 className="App">
      <h1>Get Tab Info</h1>
      <p>
        <button onClick={handleButtonClick}>URL & HTML</button>
      </p>
      <p>
        <button onClick={highlight}>Highlight</button>
      </p>
    </div>
  );
}

export default App;
반응형

댓글