前提知識
Content Scriptとは
Chrome拡張において、webページとDOMを共有しているファイルのこと。ただし、JavaScriptが実行される環境は、webページのそれと独立である。つまり、一方の環境内で定義された変数および関数は、もう一方からは触ることができない。
"run_at" : "document_start"
とにかく最速でContent Scriptを走らせるための設定。まだDOM構築もされていないし、他のscriptも読み込まれていないタイミングである。普通選ぶ必要がないが、この記事ではこの設定が前提。
webページのJS環境を触るには
webページのJS環境で実行したいスクリプトを別ファイル(あるいは文字列リテラル)で用意しておき、DOMに<script>
タグとして注入することで解決する。
(https://qiita.com/suin/items/5e1aa942e654bce442f7 および https://stackoverflow.com/questions/20499994/access-window-variable-from-content-script を参考)
問題
上記手法ではgetElementsByTagName()
でheadなりbodyなりを取得し、そこに注入したいscriptをぶら下げる方法を取っている。普通これで問題ないが、スクリプト実行をDOM構築まで待てない場合には使えない。
解決法
function injectScript(file) {
const s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.setAttribute('src', file);
return (document.head||document.documentElement).appendChild(s);
};
injectScript(chrome.runtime.getURL('/embedded-script.js'));
document.documentElement
はheadとは違い、"run_at" : "document_start"
のタイミングで呼び出しても存在している。
デベロッパーツールのSourceタブを見ると、埋め込んだ<script>
タグが、<head>
タグよりも前にあるのが確認できる。
参考
- https://developer.chrome.com/extensions/content_scripts
- https://qiita.com/suin/items/5e1aa942e654bce442f7
- https://stackoverflow.com/questions/20499994/access-window-variable-from-content-script
- https://stackoverflow.com/questions/9515704/insert-code-into-the-page-context-using-a-content-script
- http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/