見出し画像

JSXが実はベターな解だったのではないか?

JSXとHTMLベースのテンプレート言語の比較を行い、批判されがちなJSXが実はベターな解だったのでは?という記事です。

僕の結論は、HTMLとJSのどちらが制御構造を持てばいいのか?でいえばJS側が持つ方がリファクタリングしやすいため、JSXの方が良いというものです。

さて、先日、JSフレームワーク事情2020年始めという記事を書きました。これは、JavaScriptフロントエンドフレームワーク、Angularの人気が下落中という記事の元ソースであるThe State of JavaScript 2019を見ながら、React/Vue/Angularや、Next/Nuxt/Gatsbyが置かれている状況を解説するものでした。

他には、確証はないものの、Reactのシェアと人気がともに高い理由は、意外にJSXにもあるのではないか?と考えています。VueもAngularも基本的にはHTMLをベースとしたテンプレート言語を採用しています。Ruby on Railsの時代からその点は変わっていません。

JSXとはなにか

JSXは、JavaScript/TypeScriptのソースコードの中にHTMLに酷似したナニカを埋め込むものです。

他のテンプレートエンジンやテンプレートベースの言語とは考え方が逆で、JS/TSのコードが主体であり、そこにHTMLっぽい木構造を埋め込むための仕組みに過ぎません。

babelなどのトランスパイラはHTMLのようなものを、デフォルトではReact.createElement()という関数呼び出し、つまりJSのコードに置換します。文字列はいい感じにエスケープされますし、波括弧で囲われた部分もJavaScriptのコードとして使われます。

JSXは決して、テンプレートの中にロジックを埋め込むものではありません。

応用例としては、MDXというMarkdownの中にJSXを入れるものや、JSXを使ってPowerpointデータを作成するというものがあります。

このプレゼンを見ると分かりますが、JSXはただの木構造に過ぎません。こういう応用には無限の可能性を感じます。

HTMLテンプレートとは何か

HTMLテンプレートでは v-if v-for や ng-if ng-repeat という独自のディレクティブに制御用のコードとしてJSの断片やDSLを埋め込みます。HTMLが主であり、制御が必要な時にJSもしくはDSLを差し込むという考え方です。

これはRubyやPHPなどの従来のウェブアプリケーション開発の概念と同じであるため、考え方としては馴染みやすいものでしょう。

Rubyは、一部のほんの特殊な例外を覗いては、ウェブブラウザ上では動作しないため、Ruby/PHP、テンプレート言語、 JavaScript という組み合わせが使われてきました。

そもそも、古き良きHTML+JSの素朴な時代からHTMLの属性の中にJSのコードは紛れ込んでいました。

HTMLテンプレートは mustache などが有名なところでしょう。ウェブサイトの静的ジェネレータなど、様々なところでも利用されています。

AngularJS/AngularやVueもそういったHTMLテンプレートを踏襲しています。基本的にはHTMLとしてvalidなものを動的に書き換えるような考え方です。実際にはもっと最適化されてはいますが。

v-if や ng-if のようなディレクティブでは、そのディレクティブを持つタグとその中にあるものを、レンダリングするかどうかを制御します。

v-for や ng-repeat のようなディレクティブでは、イテラブルを展開し、複数の要素をレンダリングします。

個人的に感じるHTMLテンプレートの問題点

個人的にはこのやり方、とくにif分岐が存在することがテンプレートの肥大化につながり、シンプルさが損なわれると考えています。

<Hoge if="mode===1">...</Hoge>
<Fuga if="mode===2">...</Fuga>
... 以下 mode が幾つも続く

のような例は極端かもしれませんが、容易にこのようなコードが書かれてしまいます。

<Hoge if="flag">...</Hoge>
<Fuga else>...</Fuga>

を複雑と感じるかどうかはその人次第かもしれませんが、個人的には複雑性を感じます。see. 循環的複雑度

JSXの場合はそもそも分岐があるときには、

switch (mode) {
  case 1:
    return <Hoge>...</Hoge>
  case 2:
    return <Fuga>...</Fuga>
  ...
}

のようにJSXの主体であるJS/TS側で制御を行います。あるいは、予め変数に代入しておくやり方があります。

let content
switch (mode) {
  case 1:
    content = <Hoge>...</Hoge>
    break
  case 2:
    content = <Fuga>...</Fuga>
    break
  ...
}

return <Container>{content}</Content>

JSXではJS/TSが主体であるため、HTMLに制御構造が必要になっても、JS/TSのコードで木構造を制御すればいいだけです。リファクタリングも色々とやりようがあります。なんと言ってもJS/TSは本職のプログラミング言語であり、容易にユニットテストでもなんでも書けます。

・ JSXはJS/TSで木構造を制御・表現するために使われる
・ HTMLテンプレートでは静的に書かれた木構造の中に制御が埋め込まれる

VueやAngularJS/Angularを採用しているコードを読んだとき、HTMLに制御コードが埋め込まれることによる肥大化を度々見かけます。

また、ディレクティブを自作すると、ディレクティブによってどういう働きをするかという覚える・調べるべき情報量が増えます。これもディレクティブとして指定したDSLを制御するという、木構造をJS/TSで制御する以上の複雑性を持ったものです。

結論

JSXは、JS/TSのコードが主であり、単に木構造をコードの中で表現する拡張にすぎないため、変数に代入する、関数分割する、引数でやりとりするなど、いくらでもリファクタリングする余地があります。

HTMLテンプレートを使いディレクティブで制御するタイプのものは、どうしてもテンプレートの肥大化との戦いになるでしょう。(より良い方法があって肥大化せずに済むならぜひ教えて下さい)

制御構造という複雑性をHTML側に押し付けるのか?それともJS/TS側に押し付けるのか?という違いに過ぎませんが、JS/TSはプログラミング言語であるため、リファクタリングしやすいという点で有利だと思います。というだけの記事でした。

この記事が気に入ったらサポートをしてみませんか?