본문 바로가기
WEB/Chrome Extension

[Chrome Extension] content scripts를 이용해 DOM 조작하기 - 3

by IT황구 2023. 12. 3.
728x90
반응형

2023.11.28 - [WEB/Chrome Extension] - [Chrome Extension] 데이터 저장하기, storage api - 2

 

[Chrome Extension] 데이터 저장하기, storage api - 2

2023.11.26 - [WEB/Chrome Extension] - [Chrome Extension] popup 만들기, 로컬 테스트, 디버깅하기 - 1 [Chrome Extension] popup 만들기, 로컬 테스트, 디버깅하기 - 1 안녕하세요! 이번 글에서는 chrome extension을 이용해 프

rbals0445.tistory.com

 

지난 2편과 글이 이어집니다.

 

제가 의도한 chrome extension을 개발하려면 브라우저에서 Text를 다른 Text로 변경하는 기능이 필요했습니다. 이 기능을 구현하려면 DOM을 조작해야 합니다.

 

이번 글에서는 Chrome Extension의 content scripts를 이용해 DOM을 조작하는 방법에 대해서 알아보겠습니다.

 

content scripts

content scripts는 웹페이지의 문맥에서 실행되는 파일입니다. DOM에 접근해서 값을 읽고 변경할 수 있는 기능을 제공합니다.

 

웹페이지의 문맥에서 작동하기 때문에 content scripts에서 찍은 console은 현재 열려있는 브라우저의 개발자 도구에서 확인할 수 있습니다.

 

popup.js 에서 찍은 console은 chrome extension의 "팝업 검사" 에서 확인할 수 있던것과 다릅니다.

 

침고로 service-worker와 다른 개념입니다. service-worker는 중앙 이벤트 핸들러의 역할이고 여기서는 DOM을 조작할 수 없습니다.

 

popup, service-worker, content scripts 모두 다른 역할을 가진 기능들이니 구분해서 이해해야 합니다.

 

popup

  • chrome extension 아이콘 클릭시 나오는 별도의 context. 또 다른 웹 페이지
  • document.~~ 로 DOM에 접근 시 popup html의 DOM을 조작한다.

service worker

  • 이벤트 감지를 하는 중앙 이벤트 핸들러 (이벤트 처리기)
  • background 전용 개발자 도구가 따로 있다. (DOM 조작 불가)

content scripts

  • 웹페이지의 context에서 실행되는 파일. 정적, 동적으로 모두 불러올 수 있음
  • 현재 보고 있는 페이지의 DOM 조작 가능.

 

content scripts는 manifest 파일에서 설정한 url 패턴에 맞는 경우 페이지가 열릴때 정적으로 불러옵니다.

 

"chrome.scripting.executeScript"를 통해서 동적으로 불러올 수도 있습니다.

 

manifest 설정

"content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["myScript.js"]
    }
  ],

 

정적으로 불러올 파일들의 옵션들을 지정해 줄 수 있습니다.

 

matches에서 특정 url 패턴을 지정할 수 있는데, 저는 모든 페이지에서 항상 불러와야 하기 때문에 <all_urls>로 지정했습니다.

 

다른 옵션들은 아래 링크에서 확인할 수 있습니다.

 

https://developer.chrome.com/docs/extensions/mv3/manifest/content_scripts/

 

Chrome Extensions Manifest: "content_scripts" - Chrome for Developers

Reference documentation for the "content_scripts" property of manifest.json.

developer.chrome.com

 

content scripts에서는 현재 드래그한 내용을 가져와서 다른 값으로 변경시켜주는 (DOM을 조작하는) 기능이 있었습니다.

// contentScript
const userDefinedTextMap = {};

function init() {
  document.addEventListener("keydown", textReplace);
  updateMap();
}

function updateMap() {
  getStorageValue(null).then((result) => {
    Object.keys(result).forEach((key) => {
      userDefinedTextMap[key] = result[key];
    });
  });
}

function getStorageValue(key) {
  return new Promise((resolve) => {
    chrome.storage.local.get(key, (result) => {
      resolve(result);
    });
  });
}

function textReplace(event) {
  if (event.key === ".") {
    const selection = window.getSelection();
    const selectedString = selection.toString();
    const registeredText = userDefinedTextMap[selectedString];

    if (selectedString.length === 0 || typeof registeredText === "undefined") {
      return;
    }

    const $inputNode = document.activeElement; // 현재 활성화된 요소를 가져옴

    // 요소가 input 또는 textarea인지 확인
    if ($inputNode.tagName === "INPUT" || $inputNode.tagName === "TEXTAREA") {
      const start = $inputNode.selectionStart; // 선택 시작 위치
      const end = $inputNode.selectionEnd; // 선택 끝 위치

      if (start !== end) {
        // 텍스트가 선택되었는지 확인
        const curText = $inputNode.value;

        $inputNode.value =
          curText.substring(0, start) + registeredText + curText.substring(end);

        $inputNode.selectionStart = $inputNode.selectionEnd =
          start + registeredText.length; // 커서 위치를 변경된 텍스트 끝으로 이동
      }
    }
  }
}

 

하지만 해당 옵션만으로는 chrome extension을 켜놓은 상태가 아니라면 작동하지 않았습니다.

 

host_permission 설정하기

 

 

content scripts 옵션을 주었는데도 DOM 조작이 되지 않았습니다.

그러다 문득 다른 extension은 어떻게 되는거지? 라는 생각이 들었고 이것저것 눌러보던 중 차이점을 발견했습니다.

 

DOM 조작이 되는 extension은 아래처럼 설정이 되어있었습니다.

extension icon 우클릭 -> 사이트 데이터를 읽고 변경할 수 있음 -> 모든 사이트에서

 

데이터의 조작을 허락해주는 옵션이 있을것이라 생각하고 찾아보니 host_permission을 알게 되었습니다.

 

https://developer.chrome.com/docs/extensions/mv3/declare_permissions/#host-permissions

 

Chrome Extensions Declare permissions - Chrome for Developers

An overview of the valid values for the permissions property in manifest.json.

developer.chrome.com

 

manifest.json

 "permissions": ["activeTab", "scripting", "storage"],
"host_permissions": ["<all_urls>"],
"content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["myScript.js"]
    }
]

 

manifest.json 파일에 host_permission을 추가한 후 모든 사이트에서 작동하도록 변경했습니다.

 

이후 값이 정상적으로 변경되는것을 확인할 수 있었습니다.

 

마무리

 

content scripts를 이용해 브라우저에서 바로 변경해서 사용할 수 있게 되었습니다.

 

하지만 여기에도 문제가 있습니다.

 

content scripts는 웹페이지 로드시에 chrome storage의 key, value를 미리 object에 넣습니다. 그 이후 문자열을 치환할때 해당 object를 이용해 빠르게 변경합니다.

 

하지만 popup에서 새롭게 key, value를 추가한 경우 content scripts는 바로 업데이트 되지 않는 문제가 발생합니다.

이를 해결하려면 브라우저를 새로고침 해야합니다.

 

새로고침 하는 방법 대신 popup -> content scripts에 message를 보내면 바로 업데이트를 할 수 있습니다.

 

다음 글에서는 popup, content scripts간 메세지 통신 방법에 대해서 알아보겠습니다.

 

감사합니다

 

728x90
반응형