こんにちは、さち です。
先日、Firefox のアドオン「Tampermonkey」で、とあるサイト用のユーザースクリプトを書いていました。
動作テストをすると、なぜか「ユーザースクリプト」が2回実行される問題が発生。
今回は、この現象の解決方法について書いていきます。
ユーザースクリプトが2回実行される
- テスト用のユーザースクリプトを作りました。ユーザースクリプトが実行されるとコンソールにログが表示されます。
// ==UserScript== // @name Test Userscript // @namespace http://tampermonkey.net/ // @version 0.1 // @description test // @author uminosachi // @match http://example.com/ // @grant none // ==/UserScript== (function() { console.log('ユーザースクリプト 実行'); })(); - Firefox の「コンソール(Ctrl + Shift + K)」で確認してみると、ユーザースクリプトが2回も実行されています。

同じユーザースクリプトでも、「Greasemonkey」で動かすと1回しか実行されませんでした。
「Tampermonkey」とは挙動が異なるようです。
解決方法
色々と調べた結果、原因は「iframe」内でもユーザースクリプトが実行されているからでした。スクリプトにおまじないを書いてフレームを無視するようにしましょう。
- 9行目のように
==UserScript==内に@noframesを追記します。// ==UserScript== // @name Test Userscript // @namespace http://tampermonkey.net/ // @version 0.1 // @description test // @author uminosachi // @match http://example.com/ // @grant none // @noframes // ==/UserScript== (function() { console.log('ユーザースクリプト 実行'); })(); - これで、ユーザースクリプトの実行は1回だけになります。

「Tampermonkey」の場合、問題が発生した「ユーザースクリプト」のエディター画面から「設定」タブを開き、「最上位フレーム(top)のみで実行する」を「はい」にしても同じ効果が得られます。

当然、「最上位フレーム(top)のみで実行する」は、自分のブラウザでのみ有効な設定です。配布する予定があるものは、スクリプト内に @noframes を記述しましょう。
多くのユーザースクリプトはフレーム内での実行を想定していないと思うので、「Tampermonkey」のテンプレートに追記しておいても良いかもしれません。
余談 - 自力実装してみる
前述のような用意されているものを使わないで、JavaScript だけで自力実装する場合はこうなります。
// ==UserScript==
// @name Test Userscript
// @namespace http://tampermonkey.net/
// @version 0.1
// @description test
// @author uminosachi
// @match http://example.com/
// @grant none
// ==/UserScript==
(function() {
if(top !== self) return false;
console.log('ユーザースクリプト 実行');
})();
top は window.top の省略記述で、トップフレームの URL
self は window.self の省略記述で、現在のフレームの URL です。
この両者が一致しない時は、フレーム内での実行なのでスクリプトを終了します。これで、スクリプトの実行は(トップフレームでの)1回だけになります。
原理的には自分のサイトがフレームで他サイトに読み込まれるのを防ぐ方法と同じですね。


コメント