Hatena::Groupptech

ぷちてく RSSフィード

Archive
 
ProfileProfile

2014-11-12

ユーザースクリプトの@noframes

04:10

どーもこんちわ。久しぶりにUserScriptのMetadata Blockの話。

先月リリースされたGreasemonkey 2.3 で@noframesが実装され、主要なGM実行エンジン間でようやく共通して使えるようになった。

Added @noframes metadata imperative

Greasespot: Greasemonkey 2.3 Release

殆どのUserScriptはiframe内で走る必要は無い。明示的に止めたい場合、これまでは古のframe魔術を使ってこう書いていた。

(function () {
    // run only in top-frame (w/o iframes)
    if (window.top !== window.self) return;
//...
})();
auto syntax highlighting by google-code-prettify with Pager Extension for UserScript/Bookmarklet ? GitHub

自身が最上位ウインドウか判定して、iframeだったら中断する。こういう面倒な処理が、ヘッダに@noframesを足すだけで良くなった。

// ==UserScript==
//...
// @noframes 
// ==/UserScript==

UserScriptエンジンがこれを規定の動作にしないのが不思議。おそらく、暗黙的に使ってた今までの財産がぶっ壊れるとかそんな理由で踏み切れないのでは、と勝手に思ってる。

もちろん埋め込みコンテンツを書き換えたりするには必要で、動かない副作用の方が大きいからそのままの仕様なのかもしれない。

ここまでで意味がわかった人は次のセクション読む必要ないので、読み飛ばそう。

必要な理由とか背景を飛ばす


@noframesが何故必要か

以下大雑把な話。中々気づきにくいのだけど、ページの中にwindowというのは大抵複数ある。1つで無いことの方が多い。

windowがグローバルのトップレベルオブジェクトって習ったのに!?という感じで意味わからないかもしれない。このような簡単なUserScriptを用意したので適当なページで走らせてみるといい。

(function () {
    console && console.debug && console.debug(window);
})();
log main window and iframes for UserScript ? GitHub

するとこうなる。windowが複数回出力されてるのがわかると思う。

f:id:noromanba:20141113032511p:image

この世は地獄になってしまい、クロスドメインを実現するためYoutubeやらブログパーツやら何でもかんでもiframeで埋め込まれるようになった。

iframeはその名の通り、別のページをインラインで埋め込むもので、メインとは別のwindowがぶら下がっている。UserScriptはそれぞれのwindow分だけ走る仕組みになっているので、予期せぬ動作やパフォーマンスの低下が起きる場合がある。

そういった問題が出る場合、@noframesすることで、1つのページで無駄に実行される事がなくなる。めでたいですね。


Greasemonkeyへの苦悩

今回の実装めでたいけど遅すぎる。Greasemonkeyはガチガチの保守なので新機能の慎重さには定評があり、耐えかねた人々によりScriptishが作られた経緯がある。他の主要エンジンはとっくに@noframes実装していた。

ところがUserScript界のデファクト/リファレンスGreasemonkeyな実情もあり、おいそれと独自機能使ってエンジンを限定する、というのは現実的でない。

今のUserScript、クロスブラウザでコードを共有してハックしよう、というコンセプトなのに、Metadataの機能によってエンジン間で分断が起きるというジレンマがあり、とても苦しい。

関連

トラックバック - http://ptech.g.hatena.ne.jp/noromanba/20141112