本記事では、The Elm Architecture を容易に破壊しうる闇の技術「img onerror芸」をご紹介します。
原則として「img onerror芸」は使わないに越したことはないですが、危険🐐スクリプト芸のように、ごくまれにメリットがデメリットを上回る場合があるかもしれません。
「危険🐐スクリプト芸」と同じく基本的に飛び道具的な内容のため、乱用は絶対にさけましょう。
The Elm Architecture の脆弱性をついたような技法なので何が起きても知りません。
以下の内容はバージョン0.18 を想定しています。
img onerror 芸とは
XSS脆弱性をつくときによく使われる
<img src="1" onerror="alert(1)">
を悪用した非推奨テクニックです。
念のため上記のHTMLを説明しておくと、img
タグの src
に存在しないパスを設定することで意図的に onerror
を発火させ、任意のJSを実行する手法です。
では、Elmで以下のようなViewを作成するとどうなるでしょうか?
{-| An evil view that sends `Msg` on rendering.
-}
onRenderThis : msg -> Html msg
onRenderThis msg =
Html.img
[ Attributes.src ""
, Events.on "error" <| Json.succeed msg
]
[]
上記のテクニックと同じように、この img
タグが画面上に描画された瞬間に Events.on "error"
の部分が発火するため、
「あるViewが実際に画面に描画された瞬間に任意の Msg
を飛ばして update
関数を実行する」というハックが可能になります。
The Elm Architecture をこわすので絶対にやらない方が良いですね。
Elm 0.23 くらいで使用禁止になるかもしれません。
elm-evil-sendmsg というライブラリになっているので、どうしても使いたいときにはこれを使うとお手軽でいいでしょう。
つかいどころ
もう一度言います。 使うべきではありません。
ちょっとだけ便利になるかもしれないパターンは、たとえば以下のようなユースケースでしょうか?
特定のDOMに対して port
でJSのコードを適用したい場合
DOM更新後にJSを実行する方法 がちゃんと用意されているのでこちらを使いましょう。
でも、DOMを作成するタイミングがあまりにも複雑で、update
関数のどこでそのDOMを作成するかがわかりにくい場合、img onerror芸を使うとちょっとすっきりします。
でも、すっきりするだけでそんなバッドハックを使ったらダメです。
update
関数の書き方を工夫すればいくらでもすっきり書けるはずです。
Model の値を監視する
Evil.SendMsg.when を使えば、Modelの特定の値を監視して、閾値を超えたら Msg を発行するような実装が可能になります。
elm-evil-sendmsgのデモでは、さくらちゃんがデレる閾値の検出に Evil.SendMsg.when
を利用しています。
でも、update
関数で常に対象の値をチェックしたら同じことができます。
ちょっと簡単になるからってこんなバッドハックを使ったらダメです。
ボタンを押す処理を代替する
elm-evil-sendmsgのデモでは、さくらちゃんとの会話を進めるために「Click to Next」のボタンを押す必要がありますが、「Auto」ボタンを押すと自動で会話が進んでいきます。
この挙動を
- ユーザーの行動によって Msg を発行するボタン
- 画面に表示された瞬間に Msg を発行するボタン
と抽象化して考えるととてもすっきり実装できます。
でも、これも本当は update
関数で会話を進めるときに Auto ボタンが押されているかチェックして動作を分岐させるのが正しいやり方です。
「抽象化できてるオレかっけー」と思ってバッドハックを使うのはダメです。