JavaScript Framework TodoMVC Size Comparison を掘っていく
Solid.js の作者である Ryan Carniato氏 が、TodoMVCコンポーネントを題材に各JavaScript Frameworkの出力のサイズについて比較しています。
@jay-es さんが日本語に翻訳してくださっています。
これについて意見を書いていきます。
この記事のベースは VueやViteなどの作者として知られる Evan You 氏がVueとSvelteのサイズについて比較検証を行ったものが始まりとなっています。
私はこの比較検証についていくつか調査をしていて、途中で興味が逸れて書くのをストップしました。
実はこの調査のときに、Ryanさんが記事に書いたことを私も検証していて、実際にコードまで書いてそのときにあることに気が付き、それで興味がなくなったのです。それについて記載していくスクラップです。
前置きとして記載しておきたいのが、実際にコンポーネント数が多くなると Solid.js や Preact はバンドルサイズが小さくなる、ということです。それについては正しいです。
実際、私が前回書いたスクラップでもそれについて触れようとは考えていて、スクラップの最後のほうに書きたいこととして
- preactの凄さ
- solidjs凄そう
を挙げています。
では主題に移ります。
結論から書くと、JavaScript Framework TodoMVC Size Comparison に書いてある計算はあまり意味がありません。同じTodoMVCコンポーネントを複数ファイル分用意し、それをインポートしてビルドしても計算通りになりません。コード量がいくらあっても、同じ内容だったら圧縮されるからです。重複は圧縮アルゴリズムの大好物ですから。
具体的にはこのようになります。
※検証ができたのは実際にソースが用意されている Vue と Svelte だけで、追加検証したのはコンポーネント数80個のケースだけなのでデータを絞っています。
JavaScript Framework TodoMVC Size Comparison に書いてある計算値
1 | 80 | |
---|---|---|
Svelte | 3.73kb | 152.25kb |
Vue | 17.99kb | 104.89kb |
実際にビルドして計測された値
1 | 80 | |
---|---|---|
Svelte | 3.73kb | 8.45kb (1.92 + 6.53) |
Vue | 17.99kb | 21.01kb (16.89 + 4.12) |
-
Svelte
-
Vue
ソースはこちら。
ええ、もちろんこんなビルド結果になんの意味もありません。同じ内容のコンポーネントをわざわざ別ファイルにしてそれをインポートしてビルドすることなんてないでしょうから。
この記事や「vue-svelte-size-analysis」で言いたいのは TodoMVC サイズ のコンポーネントがいくつあるのか、ということですよね。つまりコードに重複がないようなコンポーネントを何種類並べたら、ということです。
それってどんなコードでしょうか。
そこで、もう一歩進んで色んな種類のコンポーネントを用意して検証しようと思いましたが、上手いことサイズを増やせるようなコンポーネントを各フレームワーク分用意するのは非常に手間がかかり、断念しました。
(実際にはTodoMVCとjs-framework-benchmarkのコンポーネント、つまり2種類だけ用意して検証はしました。検証した結果、やはりリニアには増加せず、Svelteの場合はvendorチャンクを除いた合計値から8.4%ほど、Vueの場合はvendorチャンクを除いた合計値から7%ほどサイズが小さかったです。たった2種類だけでもそこそこ数字が変わる、しかもサイズの増加量が大きいものほど圧縮される量も多かったです。そしてさらに同じようなコンポーネントを各フレームワーク分用意することができなかったためこれ以上の検証を断念しました。)
どのフレームワークでも、コンポーネントのファイルには html や javascript、あるいはそのサブセットやそれに似せた DSL で構成された文字列が書き込まれています。構文や関数、メソッドには限りがあり、重複が少ないコンポーネントを何十種類も用意することは非常に難しいです。
実際のプロダクションのコードには、重複が多いものから重複が少ないものまで様々なコンポーネントが様々なサイズで存在しています。もしフレームワークのJavaScriptのバンドルサイズが知りたいなら、プロダクションに近いコードで比較しなければ意味がありません。
また、単一ページにTodoMVCサイズのコンポーネントを何十個も使用することなんて現実的にあり得るだろうか、という疑問も湧いてきました。もしあるとしたら、それがボトルネックです。それよりは適切にコード分割をしてくれるようなメタフレームワークを使用したほうがよいでしょう。
このあたりで、私は TodoMVC 単体の比較について興味がなくなっていきました。
コンポーネントが増えるとSolid.js や Preact のバンドルサイズは小さくなり、逆に Svelte のバンドルサイズが大きくなる傾向があるのは正しいです。そしてコンポーネント1つ1つが小さいほうがパフォーマンス良いのも間違いありません(もちろんランタイムも小さい方が良いです)。
しかし、残念ながらこの「JavaScript Framework TodoMVC Size Comparison」はそれを裏付けられるものではありません。
ではどういうものならそれを裏付けるものになるでしょうか。
個人的には、RealWorld App のバンドルサイズが適切かと思います。
プロダクションのコードというものはそれぞれのソフトウェアで全く異なるでしょうけれど、同じコンポーネントの出力サイズをただ積み重ねていくよりは RealWorld App のほうが現実に近いと言えるでしょう。
Solid.js の公式サイトには次のような記述があります。
Solid の RealWorld デモの実装は、Svelte の実装よりも 25% 小さいです。
私は実際にビルドしていないので確認していませんが、公式サイトですし、Ryan Carniato 氏はフェアな方ですので嘘は言っていないと思います(私が彼のファンだというバイアスはあるかもしれません)。
こちらのほうがより現実に近い数字かと思います。
まとめです。
Solid.js や Preact はコンポーネント数が増えると他のフレームワークよりサイズが小さくなるが、「JavaScript Framework TodoMVC Size Comparison」はその例としてあまり適切ではない。RealWorld Appなどの多くの種類のコンポーネントが使用されている例のほうが適切である。
なお、この意見をもうちょっとまとめてから原文にコメントしようと思ってます。
当時私が実際に検証を行ったときと同じようなコードをもう一度構築し、そこで計測された値を↑のほうに貼り付けました。
原文のコメントを見たら、私がコメントしようとしていたことと同じようなことをコメントしてくださっていた方がいらっしゃいました。つまり「もっと大規模なアプリのほうが(比較のためには)良いのでは?」ということです。
そしてそれに対する回答もありました。
その回答を抜粋させていただきます。
Finally if the hope were to look at real sites in the wild. In a sense that would be best but the sample size would need to be enormous and need to figure out how to be representative not to be unfair to more popular frameworks used in less optimal ways.
サンプルが膨大になるのと、適切でない方法でベンチマークを取られてしまうフレームワークにとっては不公平になってしまう、ということですね。
フェアであろうとする姿勢がかっこいいですね。
当時私が検証していたことについて数字も載せることができ、コメントしようとしていたことについては既に同じようなコメントがありそれも記載できたのでこのスクラップはCloseします。
余談ですが、普通に記事を書くよりスクラップのほうがこまめに情報を足すことができ、ハードルが下がるので書きやすいですね。