티스토리 뷰

발생일: 2013.03.07

문제:
며칠 전 M 과장님이 영어사전 크롬 익스텐션의 신기한 버그를 하나 알려줬다.

과장님이 개발하고 있는 페이지에서 require.js 를 사용하고 있는데,
영어사전 익스텐션이 설치되어 있는 경우엔 메인 코드가 두 번 호출된다는 거다.

익스텐션에서도 require.js 를 사용하고 있긴 한데,..
require.js 가 두 번 로드되면서 뭔가 충돌이 일어난 것 같다.

정확한 원인이 뭘까?


해결책:

먼저, require.js 가 메인 코드를 가져와 실행하는 과정은 다음과 같다.

  <script src="require.js" data-main="main"></script>

  1. require.js 가 로드되면, 페이지 내에서 <script> 태그를 찾고,
  2. 각 태그 내의 `data-main` 속성에 정의되어 있는 모듈명을 의존 목록에 추가한다.
  3. 위의 메인 모듈을 의존 목록으로 갖고 require를 호출한다.


또한, 아래와 같이 페이지 내에 require.js 가 중복으로 정의되어 있어도,
메인 코드가 여러 번 호출되진 않는다.

  <script src="require.js" data-main="main"></script>
  <script src="require.js"></script>


require.js 에서 코드를 초기화할 때,
전역 변수인 `requirejs, require, define` 가 이미 존재할 경우 중복 정의하지 않기 때문이다.


하지만, 익스텐션의 경우는 이야기가 다르다.

익스텐션의 컨텐트 스크립트는 페이지의 컨텍스트에서 실행되고, DOM에 접근할 수 있다.
하지만, 컨텐트 스크립트 만의 샌드박스가 있기 때문에(이 환경을 isolated world 라고 표현한다),
페이지 내의 스크립트에는 접근하지 못한다.
마찬가지로 페이지 내의 스크립트도 컨텐트 스크립트에 접근할 수 없다.


문제가 발생한 환경에서는,
페이지 내에서 require.js 를 한 번 로드하고, 익스텐션에서 require.js 를 다시 로드했다.

페이지 내에서 이미 `requirejs, require, define` 전역 변수를 선언했지만,
익스텐션의 실행 환경에서는 페이지에서 정의한 위 변수에 접근할 수 없기 때문에,
익스텐션의 require.js 가 로드되면서 다시 초기화를 시도한 것이다.

초기화 시 문서의 모든 스크립트에서 `data-main` 속성을 찾아 메인 모듈을 호출하기 때문에,
페이지 내에 정의했던 메인 코드가 두 번 호출된 거였다.
(컨텐트 스크립트가 DOM에는 접근할 수 있으므로)


익스텐션에서 페이지 내에 이미 require.js 가 로드되었는지 여부를 알 수 있는 방법이 없기에,
익스텐션의 require.js 를 직접 수정해 data-main 코드를 가져오지 않는 방법으로 해결했다.








반응형
댓글
공지사항