Safari extension으로 먼저 나온 바른 말씨를 Google Chrome 용으로도 배포할 목적으로 개발하면서 부딪혔던 문제로, 대부분의 extension APIs와 그 구조는 서로 닮았기 때문에 코드 이전에는 별다른 어려움은 없었다. 그런데 한 가지 커다란 장벽과 마주쳤으니.
보통 extensions에 의해 페이지에 삽입되는 Content Scripts는 독립적인 sandbox 환경에서 실행되면서 원래 웹 페이지에 존재하는 스크립트와의 간섭을 걱정할 필요 없이 DOM을 만질 수 있게 되는데, 불행히도 Google Chrome extensions에선 iframes 접근이 차단되어 있어서 window.frames 값으로 undefined를 돌려준다. 이 문제는 알려진 버그로, 해결책으로 다음과 같이 Background Page에서 chrome.tabs.executeScript() 명령으로 해당 사이트의 DOM에다 직접 script tag을 생성해서 Chrome의 Sandbox 밖에서 실행되는 스크립트를 삽입해 주는 것이다.
chrome.tabs.executeScript(null, {file: 'scriptInjecting.js'}, scriptInjected);
script tag를 만들고 Sandbox를 탈출해서 실행될 스크립트를 삽입하는 scriptInjecting.js
파일의 내용은 다음과 같다.
(function(doc) {
var s = doc.createElement('script');
s.type = 'text/javascript';
s.src = chrome.extension.getURL("escapedFromChromeSandbox.js");
var x = doc.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
})(document);
이렇게 해서 삽입된 escapedFromChromeSandbox.js
파일에선 iframes의 속 내용을 들여다볼 수 있게 된다.
여기서 얻어진 정보는 가령, hidden input을 만들고 이놈의 value나 title 혹은 data 속성에다가 저장해 놓기만 하면, 나머진 종전처럼 해당 페이지의 DOM 접근이 가능한 Content Scripts에서 이곳에 저장된 정보를 읽고 message passing을 통해 background pages에 전달해주면 된다.
이 밖에도 사소한 것으로, 검사 결과를 보여주는 창을 마우스로 잡아서 이동시킬 수 있도록 하는 기능을 구현하는데, Safari에선 별문제 없던, HTML5의 Drag and Drop 기능을 빌려 쓰려 하였으나 drag시 마우스의 위치 값을 제대로 돌려받지 못하는 문제도 있어서 결국 약간 소모적일 수도 있는 Mouse events를 써야만 했다.
최근 많은 브라우저가 extensions 혹은 add-ons 형태로 사용자 입맛에 맞는 추가 기능을 제공하는 추세이고 또 각 브라우저가 가지고 있는 고유 API와 그 구현 방식도 서로의 차이점이 줄어들고 있기는 하지만, 아직은 개발자에게 혼동을 일으킬 수 있는 미묘한 차이를 보이면서 앞으로 어떤 통합된 개발 환경이 제공되었으면 하는 바람도 가지게 된다.