NOMO.asia

최근 Firefox 57.0 버전으로 업데이트 했는데, 몇몇 유저스크립트가 작동하지 않아서 확인해보니 아래 두가지가 문제였다.

1.Greasemonkey 4 확장기능은 57.0 에서 GM_setValue 함수를 지원하지 않는다.

GM_setValue 함수는 확장기능이 관리하는 저장소에 유저 설정, 캐시 데이터 등 값을 저장하기 위하여 쓰인다.
그런데 Greasemonkey 4 에서는 해당 함수를 지원하지 않는다고 한다. 정확히는 GM dot 함수로 바뀌었다.

Greasemonkey 4 Announcement (https://www.greasespot.net/2017/09/greasemonkey-4-for-script-authors.html)
위 문서를 참고해보니 기존의 GM_ 함수는 동기식이었고, 이것을 비동기식으로 바꾸기 위하여 작업을 한 결과가 GM dot 함수라고 한다. GM.setValue 처럼 GM 에 dot(.)을 붙인 함수의 형태로 쓴다는데, 그냥 함수만 바꾸면 되는 것은 아니고 사용법까지 달라지니 위 문서를 참조하는 것이 좋겠다. 제공되는 polyfill.js 를 이용하여 기존 유저스크립트 또는 다른 Userscript 엔진과도 호환성을 유지하는 방법도 나와있다.
async 와 await 에 대해서는 이 문서 에 예제가 잘 나와있다.

개발자 입장에서 근본적인 해결 방법은 코드 수정이겠지만, 만약 당신이 단순한 유저스크립트 사용자라면 Greasemonkey 확장기능의 사용 대신에 violentmonkey 확장기능을 사용하면 기존의 GM_setValue 함수를 지원하므로 간단히 해결할 수 있다.


2. 1번을 해결한 이후 나타난 문제는 exportFunction 함수가 undefined 라고 나오는 문제이다. 

(exportFunction 함수를 어디에, 왜 사용하는지는 http://nomo.asia/340 를 참고)
Firefox 57.0 에서 지원하지 않는 것인지 아니면 Violentmonkey 에서 지원하지 않는 것인지는 확인해보지 않았다. 일단 위의 Greasemonkey 4 Announcement 문서에서는 unsafeWindow 보다 cloneInto and exportFunction 를 사용하라고 설명하고 있는 것 같은데 왜 안 되는지는 잘 모르겠다.


$(document).ready(function(){

unsafeWindow.fB = function() {

            // 새로운 function 내용

 console.log("fB was hijacked!");

 };

})



출처: http://nomo.asia/340 [이름없음]

참고로 당시 상황은 아래와 같았다.

  1. Userscript 를 적용할 페이지에서 로드하는 js 파일 내에 fA, fB 라는 이름의 함수(function) 가 존재한다.
  2. fA 함수의 내부에서는 fB를 호출한다.
  3. 내가 Userscript를 이용하여 덮어씌우고 싶은(Override) 함수는 fB 함수이다.

Chrome 은 그냥 아래와 같이 하면 잘 됐었다.

$(document).ready(function(){
    unsafeWindow.fB = function() {
            // 새로운 function 내용
    console.log("fB was hijacked!");
    };
})


Firefox 는 위와 같이 하면 안 돼서 아래와 같은 방법을 썼었다.

$(document).ready(function(){
    newfB = function() {
        // 새로운 function 내용
        console.log("fB was hijacked!");
    };
    unsafeWindow.fB = exportFunction (newfB, unsafeWindow);
    newfA = function() {
        newfB(); // fB 를 newfB로 대체한다.
        console.log("fA was hijacked!");
    };
    unsafeWindow.fA = exportFunction (newfA, unsafeWindow);
})

$(document).ready(function(){

unsafeWindow.fB = function() {

            // 새로운 function 내용

 console.log("fB was hijacked!");

 };

})



출처: http://nomo.asia/340 [이름없음]

Chrome 의 경우 별 문제가 없다. 아래와 같이 하면 문제 없이 작동한다. 내가 바꾸고싶은 함수는 fB 뿐이므로 fB의 내용만 바꿔주었다.


$(document).ready(function(){

unsafeWindow.fB = function() {

            // 새로운 function 내용

 console.log("fB was hijacked!");

 };

})


run-at : document-start 조건을 추가하였으므로, document ready 내에 hijacking 코드를 추가해주어야 제대로 적용된다.



출처: http://nomo.asia/340 [이름없음]


$(document).ready(function(){

unsafeWindow.fB = function() {

            // 새로운 function 내용

 console.log("fB was hijacked!");

 };

})



출처: http://nomo.asia/340 [이름없음]


$(document).ready(function(){

unsafeWindow.fB = function() {

            // 새로운 function 내용

 console.log("fB was hijacked!");

 };

})



출처: http://nomo.asia/340 [이름없음]


해결 방법은, 그냥 Chrome 처럼 하면 잘 된다. 이게 Firefox 57.0 이라서 그런건지 Greasemonkey 와 Violentmonkey 의 차이인지는 모르겠지만, 또는 내 코드가 바뀌어서 그런건지는 모르겠지만 Chrome 의 경우처럼 하면 잘 된다. 다만 기존에 브라우저별 호환성을 위해 분기를 해놓았었는데 해당 부분을 아래와 같이 수정했다.

if( (web_browser === 'firefox') && (typeof exportFunction === 'function') ){
    // Firefox 57.0 미만 & Greasemonkey 용 코드
}
else {
    // Chrome 및 Firefox 57.0 이상 & Violentmonkey 용 코드
}

여전히 Firefox 57.0 미만 버전을 사용하는 사용자도 있을 수 있기 때문에, exportFunction 함수가 정의되어 있으면 기존 분기를 사용하도록 설정했다.