chrome extension の content script は変数が隔離されている
chrome extension を作ってて、ページ内の変数やイベントハンドラを上書きしたいよね?
頻繁にイラッとして私は上書きしたいと思っています。しかし、ContentScript のJSは isolated dom world なので、おなじDOMがレイヤー化され何枚も載っています。(CSSのようにレイヤー化して、DOM空間を隔離している)
手が出せない。。。DOM
ページ側
document.oncontextmenu = some_function
content script 側
document.oncontextmenu = null; //上書きできない
実行タイミングを制御してもダメ。
content scripts には run_at があるので、実行タイミングを色々変えることをやりたくなりますが、コレは徒労に終わる。
documentに記述されたScriptタグ内で設定されたdocument.onload などのプロパティ値にもアクセス出来ない
ページ側のDOMや変数にアクセスする手段。
- script タグを createElementして appendChild
- location.href に javacript:: を書いて強制実行
他にも、aを追加してクリックして実行するとか、まぁHTMLのbody 以下にScriptのコードを書き足して実行するという手段しかない。
例えば、こんな感じ
manifest.json
{ "manifest_version": 2, "name": "check_extension_injection", "version" : "1", "content_scripts":[ { "matches" : [ "http://*/*"], "js": ["test.js"], "run_at" : "document_end" } ] }
test.js (コンテンツに差し込むjs)
document.body.appendChild(function(){ sc = document.createElement("script"); var code = function(){ console.log("aaaaaaaaaaaaaaaa") } src = "("+code.toString()+")()" sc.type="text/javascript"; sc.text=src return sc; }() );
script.text = "実行したいコード"を書くことで、変数をいじることが出来て幸せになる。
ただ、実行したいコードをStringで書くと面倒なので、Function書いてからToString()のが味噌
実行時タイミング run_at について
run_at で、拡張機能content_scripts の実行タイミングを指定することができる
- document_start
- document_end
- document_idle (省略時デフォルト)
になるのですが。
それぞれ、よくわからないので、DOMContentLoadedイベントを差し込んで実験してみた
content_script で埋め込んだコード
document.addEventListener("DOMContentLoaded",function(){ console.log("from content_script"); })
このコードとページ内のJavaScriptと競争する。
ページ内DOMContentLoadedとinjection の DOMContentLoaded の競争
run_at | ページ内DOMContentLoaded | content_script |
---|---|---|
document_start | 後から | 先から |
document_end | 先に実行 | 実行されない |
docunent_idle | 先に実行 | 実行されない |
意外と、シンプルですね。 document_end で書いた DOMContentLoadedは実行されない。
ページ内の、$(document).ready() より先に実行しようとしたらDOMContentLoadedに放り込むのも確実っぽい。
拡張機能のcontent_script は並列実行が良く分からない?
タイムラインを見ましょう
今回は同期的に動いてるけど、書き方に依っては非同期的にScriptが一斉にGoしたりする。