manifest_version , name , version 은 필수적인 기본 메타데이터이다.
배포하기 위해서는 icon 데이터도 필요하지만 지금 당장 난 배포할 용도는 아니기에 넘어가겠다.
permissions 의 activeTab 은 사용자가 포커스가 지정된 탭에서 확장 프로그램을 실행하도록 의도적으로 선택할 수 있으며, 이렇게 하면 사용자의 개인 정보가 보호된다. 또한 Chrome은 서비스 워커가 필요하지 않으면 종료한다. storage 는 API를 사용하여 서비스 워커 세션 간에 상태를 유지한다. 마지막으로 scripting 은 웹페이지에 코드를 주입할 수 있도록 하는 권한이다.
host_permissions 의 경우 외부 도메인으로 네트워크 요청 권한 부여한다. 내가 번역을 하기 위해서 외부 api를 이용하므로 필요하다.
content_scripts 는 페이지의 콘텐츠를 읽고 수정하기 위한 스크립트에 대한 정보이다.
matches 를 통해 콘텐츠 스크립트를 삽입할 사이트를 식별할 수 있다.
background 에는 확장 프로그램의 service worker 를 사용하여 백그라운드에서 브라우저 이벤트를 모니터링할 수 있다. service worker 란, 이벤트를 처리하고 필요하지 않을 때 종료되는 특수한 JS 환경이라고 한다.
예를 들어, 서비스 워커가 수신 대기하는 첫 번째 이벤트는 chrome.runtime.onInstalled() 이다. 이 메서드를 사용하면 확장 프로그램이 초기 상태를 설정하거나 설치 시 일부 작업을 완료할 수 있다.
action은 브라우저 툴바에 표시되는 확장자 아이콘과 관련된 설정이다.
extension의 동작방식을 이미지로 간단히 잘 표현한 것이 있어서 첨부해보았다.
어떻게 구현하였나?
먼저 Cursor로 구현에 도움을 받았지만, 코드를 한줄 한줄 분석해보니 불필요한 코드들도 너무 많았다.
그래서 실제로 모든 코드를 내가 직접 설명할 수 있을 정도로 Cursor의 코드를 리뷰하고,
내가 원하는 최적의 기능을 담긴 코드만 남겨두었다.
일단 전체 내 코드는 상단 github 링크에서 보면 좋을 것 같다.
여러 파일 중 가장 중요하게 봐야할 파일은 content.js와 background.js이다.
content.js가 DOM의 변경을 탐지하는 코드라면,
background.js는 세팅 및 외부 api를 이용하여 번역을 해오는 코드이다.
content.js 에서 번역 api를 불러오면 안될까?
브라우저의 content script(웹페이지 컨텍스트)에서 외부 API로 직접 fetch 요청을 보내면,
Google 서버가 Access-Control-Allow-Origin 헤더를 보내지 않기 때문에 브라우저가 요청을 차단한다.
즉, CORS 에러가 발생하는 것이다.
반면 background.js는 브라우저 확장자 권한으로 동작하므로 background.js(서비스 워커)는 CORS 제한이 없다. 그래서 background.js를 사용하는 것이다.
번역 api를 이용하기 위해 조사해본 결과, 추천 목록은 다음과 같았다.
google cloud translate api
libreTranslate
MyMemory
근데 아쉽게도 Google과 libreTranslate는 유료 서비스였다..
그래서 MyMemory api를 사용했다. 하지만.. MyMemory도 사실 전부 무료는 아니어서 디버깅을 하다가 Time Limit에 걸렸고, 이러다가 내가 번역 api도 만들어야 하나 싶은 생각도 들었다ㅠ
→ 번역 api를 만드는 것이 아닌 Docker를 활용하여 내 로컬 서버에서 번역 서버를 실행시키도록 했다.
→ 이 내용도 아래 기술적 챌린지에서 다루겠다.
디버깅 에러 모음
사실 코드 구현 전에 더 중요하다고 생각했던 부분이 디버깅&테스트 였다.
어떻게 디버깅을 해야할까 걱정이 되었지만, 생각보다 간단했다.
Chrome의 Extension 주소로 들어간 후, 개발자 모드를 켜서 내 코드를 불러오기만 하면 끝이었다.
코드를 수정하고 extension을 새로고침만 해주면 자동으로 코드가 반영이 되었다.
⛔
Service Worker registration failed. Status code: 15
→ 이 에러는 경로 문제가 아니라, background.js에서 아래의 오류가 나서 Service Worker를 불러오지 못해 생긴 경고다.
⛔
Uncaught TypeError: Cannot read properties of undefined (reading ‘create’)
→ contextMenus를 사용하는데 권한이 없어서 생긴 에러였다.
→ manifest.json에 "permissions": ["contextMenus"]를 추가하여 해결하였다!
⛔
Error: Extension context invalidated.
→ 내가 extension을 실행하고 디버깅을 위해 탭을 바꾸면 서비스워커가 자동으로 꺼지면서 이런 에러가 생겼다.
→ 해결방법은 기술적 챌린지에서 설명하겠다.
기술적 챌린지
서비스워커 유지하기
위에 오류 모음에서 말했듯이, 탭을 바꾸면 extension의 서비스 워커가 바로 종료되는 현상이 나타났다.
서비스 워커는 이벤트가 없으면 자동으로 종료된다는 말을 보아서 아래와 같은 코드를 추가해보았다.