余白

https://blog.lacolaco.net/ に移転しました

Dartを取り巻く仮想DOM環境に対する愚痴

再来週くらいにアドベントカレンダーでも似たようなこと書くんだけどあっちはちょっとお行儀よく書かなきゃいけないのでこっちには殴り書きという感じで今思ってることを書く

登場人物

vdom

純粋なDartによる仮想DOM実装。diff/patchは型のお陰で速いし、virtual-domでできることは出来る。作者のlocalvoid氏は後でまた出てくるんだけど仮想DOM廃人っぽい。Dartでもjsでも仮想DOMのことならなんでも知ってそう。

Liquid

↑のlocalvoid氏が作ったvdomによるUIフレームワーク

React-dart

その名の通りReact.jsのDartラッパー。ポーティングではない。内部でReact.jsを呼んでる。

vdomではDartとDOMの距離が遠すぎる

仮想DOMのイベントリスナにDart側の関数を直接渡せない構造なのが最高にクソ。

VElement("button", attributes: { "onclick" : onclick() });

たったこれだけのことができない。実際にonclickイベントをDart側で受け取ろうとすると、追加するDOM要素にidやkeyを振って、ビュー初期化後に由緒正しいdocument.querySelector()でHtmlElement要素引っ張りだして、onClickイベントにリスナー噛ませるか、"onclick"属性にonclick()なりjsの関数呼び出すようにして、Dart側でdart:js使ってcontext["onclick"] = onClickみたいに無理やりJsObjectねじ込むしかない。

前者は仮想DOMがpatchされて実DOMに要素が存在している状態じゃないとnullなのでリスナー挿せない。後者はJsObjectになってしまうので複雑になると処理追えない。

しかし普通に「仮想DOMだ~わ~い」できる。アドベントカレンダーにはサンプルコードみたいなの上げる。実用には耐えない。

Liquidだとちょっとマシ

https://github.com/localvoid/liquid/blob/master/example/todo/todo.dart#L32

Liquidが実装しているComponentというシステムなら割とDart側で書けるのでよい。イベントリスナも親が一任してイベントを受け取って、それを各要素にパターンマッチで振り分けていく形なので実DOMが存在するかどうかは関係ない。現実的。

Liquidはdart:mirrors使ってる

でもDart側で全部やろうとするとやっぱり無理があるっぽくて、リフレクション使ってる。なのでdart2jsするとAngularと同じでクッソビルド遅いしクッソでかくなる。

現実解はReact-dartっぽい

https://github.com/cleandart/react-dart/blob/master/example/react_test_components.dart#L31

React.jsに乗っかってるのでReact.jsが速くなれば速くなるし、書きやすそうでもある。ドキュメントやノウハウもjsの方と共通で通るので情報が無くて困るってこともあんまりない(はず)。

どうなんこれって感じのところもある

https://github.com/cleandart/react-dart/blob/master/lib/react.dart#L19

勝手にbindとかいう関数をComponentクラスに追加してる。中身はsetStateのラッパーで、単なるシンタックスシュガーなんだけど、なんかモニョる。どうなんこれ

あと、React-dartはクライアントとサーバーどっちで動かすかみたいなところも選べる。Reactをサーバーサイドで動かすのってあんまり聞いてないけどアンテナ低いだけかな。

結論:JSXほしい

Liquidの文字列指定は嫌だし、

new VElement("div")(new VElement("h1")("Hello World"));

React-dartの関数化もコードがネスト地獄る原因である

div({}, h1({}, "Hello World"));

JSX Harmony欲しすぎる