※この記事の検証環境はElm 0.19.1です。
Elmでランタイムエラーを起こす方法をTwitterで尋ねたところ、すぐに教えてもらえました。Elmコミュニティすごい!ありがとうございます!!
attribute "" ""
— 業スーのラップ(みやも) (@miyamo_madoka) 2020年5月29日
確認
以下のコードを書いてみたところちゃんとエラーになりました。
コード
div [ attribute "" "" ] []
出てきたエラー
InvalidCharacterError: Failed to execute 'setAttribute' on 'Element': '' is not a valid attribute name.
エラーになった!やった!
なぜランタイムエラーを起こしたくなったのか
以上でこの記事終わりでいいんですが、どうしてランタイムエラーを起こしたくなったのかというのも書いておきます。
Elm製アプリケーションを運用していて、Sentryの導入を考えていました。で、JavaScript側にSentryをセットアップしたときに、Elm側で起きたエラーも拾ってくれるのだろうか...?という疑問がありました。おもむろにSentryをセットアップして、JavaScriptからエラーが飛ぶことを確認した後に、さてElm側でもエラーを起こして確認だと思ったものの、あれ、Elmってランタイムエラー起きないことを謳ってるよな。起こす方法あるの...?となりました。
なぜattribute関数でランタイムエラーを起こせたのか
これも蛇足ですが、どうしてランタイムエラーを起こせたのでしょうか。
エラーの理由は、エラー文に書いてあるとおりです。setAttributeを不正な引数で呼んだからですね。ただ、今日はせっかくの休日なのでソースコードを見てみたいと思います。https://github.com/elm/html/blob/master/src/Html.elm を見ると、DOMを吐き出す関数はこんな感じです。
node : String -> List (Attribute msg) -> List (Html msg) -> Html msg node = VirtualDom.node
なので、VirtualDom.nodeを見てみます。
node : String -> List (Attribute msg) -> List (Node msg) -> Node msg node tag = Elm.Kernel.VirtualDom.node (Elm.Kernel.VirtualDom.noScript tag)
なるほど...?
var _VirtualDom_nodeNS = F2(function(namespace, tag) { return F2(function(factList, kidList) { for (var kids = [], descendantsCount = 0; kidList.b; kidList = kidList.b) // WHILE_CONS { var kid = kidList.a; descendantsCount += (kid.__descendantsCount || 0); kids.push(kid); } descendantsCount += kids.length; return { $: __2_NODE, __tag: tag, __facts: _VirtualDom_organizeFacts(factList), __kids: kids, __namespace: namespace, __descendantsCount: descendantsCount }; }); });
なるほど!!(わからん)
深入りするとElmのVirtualDom実装理解という別テーマになってしまうので、完全理解は諦めて、このモジュールでsetAttributeしているところを見てみます。
function _VirtualDom_applyAttrs(domNode, attrs) { for (var key in attrs) { var value = attrs[key]; typeof value !== 'undefined' ? domNode.setAttribute(key, value) : domNode.removeAttribute(key); } }
ここだけ見れば難しくないです。domNodeはきっとvirtualdomがつくってくれた生DOMで、attrsはきっと {'class': 'hoge', 'id': 'fuga', ...}
みたいな連想配列でしょう。ということは、Elmのdiv [ attribute "" "" ] []
というコードを書いたとき、実行時には以下のようなことが起きているはずです。
domNode.setAttribute('', ''); // domNodeはdocument.createElement('div');相当のオブジェクト Uncaught DOMException: Failed to execute 'setAttribute' on 'Element': '' is not a valid attribute name. at <anonymous>:1:4
まとめ
ざっくり追って、どういうことかわかりました。VirtualDomに興味が出てきたので、時間があるときに今度はそちらを深追いしてみたいです。