Userscript 확장기능 별 iframe 내부에서 호출 가능 여부
Posted 2018. 12. 25. 11:01, Filed under: 개발/UserScriptiframe 내에서 작동하는 Userscript 를 코드를 작성하다가, 브라우저 확장기능 별로 iframe 내에서 Userscript 의 호출 여부가 다르다는 것을 알게되었다. 무엇보다 Firefox 의 Greasemonkey 에서는 iframe 내에서 require로 jquery를 불러와도 사용이 안 되는 경우가 있어서 다른 확장기능에서는 어떤지 테스트를 해보고 싶었다. 어떤 웹사이트에서 테스트 했는지는 비밀이다. 모든 웹사이트에서 아래와 같은 상황이 생기는 것은 아닐 것이다.
테스트한 웹사이트 구조
1. main frame ( url.com )
└ 2. iframe ( url.com/iframe.php )
└ 3. iframe ( about:blank, 즉 iframe의 src 값이 존재하지 않음. 동적으로 생기므로 생성까지 약간의 딜레이 존재함 )
최상단에 main frame 이 있고, 그 안에 첫번째 iframe 이 있고, 그 안에 src가 존재하지 않는 iframe 이 존재하는 구조이다.
마지막 iframe 은 외부 css, js 의 영향을 받지 않기 위한 목적으로 iframe 의 형태를 취한 것이라 src 값이 존재하지 않는다.
테스트한 Userscript 코드
// ==UserScript== // @name iframeTest // @namespace iframeTest // @description iframe 테스트용 코드 // @include *.url.com* // @version 0.0.1 // @require http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js // @run-at document-start // ==/UserScript== /*jshint multistr: true */ console.log('now : ',window.location); if (typeof jQuery == 'undefined') { console.log('jquery가 존재하지 않음'); console.log(document.getElementsByTagName('head')); var script = document.createElement('script'); script.type = "text/javascript"; script.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"; document.getElementsByTagName('head')[0].appendChild(script); console.log('jquery:', typeof jQuery); } else{ console.log('jquery가 존재함'); console.log(window.jQuery); console.log($(document).find('head').html()); } // 1초 뒤에 확인 setTimeout(function(){ console.log('jquery:', typeof jQuery); },1000)
결과 정리
① Firefox - Greasemonkey
run-at 값에 뭘 주느냐에 따라 결과가 다르다.
- document-start 의 경우
main frame 과 첫 번째 iframe 에서 Userscript가 호출된다.
main frame 에서는 모든 기능이 정상적으로 동작한다.
첫 번째 iframe 에서 스크립트가 호출된 직후에는 jquery 가 존재한다고 표시된다. 하지만 1초 뒤에 다시 체크해보면 jquery 가 undefined 상태가 된다. 내가 테스트 한 웹사이트에서만 이런 증상이 발생할 것 같기는 한데, 동일한 구조를 갖는 다른 웹사이트에서 테스트 해보지는 않았다. 여하튼 이러한 경우 jquery 함수를 사용하면 오류가 발생하며, jquery 를 사용하려면 Metadata block의 require 에 의존해서는 안 되고 별도의 호출 코드를 삽입하고 setTimeout 으로 딜레이를 주는 등 귀찮은 작업을 추가적으로 해야 한다. - document-end 의 경우
main frame 에서만 호출된다. jquery 사용에 문제 없다. - document-idle 의 경우
main frame 과 첫 번째 iframe 에서 호출된다. jquery 사용에 문제 없다.
② Firefox - Violentmonkey
③ Chrome - Tampermonkey
main frame 과 첫 번째 iframe 에서 Userscript가 호출된다. run-at 값에 따라 결과가 달라지지 않는다. jquery 사용에 문제 없다.
Chrome 의 Violentmonkey 에서는 테스트해보지 않았지만 큰 문제는 없을 것 같다.
2019-01-18 추가:
@include 를 *.url.com* 이 아니라 * 로 설정하여 모든 웹사이트에서 동작하도록 설정하면, Tampermonkey 에서도 두 번째 iframe 에서 호출됨을 확인하였다. 그 외 about:blank 등의 키워드는 먹히지 않았다.
최상단 프레임에서만 Userscript 를 동작시키고 싶은 경우
- Metadata block에 @noframes 를 삽입한다.
- 코드 내에서 window.top === window.self 가 true 이면 main frame, false 이면 Iframe 이다. 코드 최상단에서 iframe 인지 여부를 체크하고, iframe의 경우 return 하여 코드를 중지시키면 된다.
- location.href 을 체크, iframe 에 해당하는 주소인 경우 return 시킨다. (iframe 주소에 해당하는 리스트를 작성 필요가 있다)
만약 iframe 내에서 Userscript가 호출되지 않는다면?
//첫번째 iframe 내부 접근 $('#iframe_id1').contents().first(); //두번째 iframe 내부 접근 $('#iframe_id1').contents().first().find('#iframe_id2').contents().first();
결론
Firefox의 경우 Violentmonkey 확장 기능을 사용하는 것이 최고다.
Greasemonkey 는 Firefox Quantum 업데이트 이후 구려졌으므로 쓰지말자.