Vue, JSX, Polymer...なぜJavaScript、HTML、CSSを一緒にしたがるのか


JavaScriptとHTMLとCSSはわけたほうがいいのに、そう思ってた時期が私にもありました。

ですが、一緒くたにする妥当な理由があったみたいです。

二つの指針

コンポーネントのモジュラリティを図るのに重要な指針が二つあります。凝集性と疎結合性です。

凝集性はモジュール内のプログラム片同士の依存度の高さです。
疎結合性はモジュール間の依存度の低さです。

両者が高いのが、モジュラリティの高いコンポーネントです。モジュラリティの高いコンポーネント同士を組み合わせると、問題を不要に複雑にすることなく解決することができます。

JavaScript HTML CSS

HTMLは文書構造、CSSは見た目、JavaScriptは動作とわけられます。
これはjQueryが目指した世界でもあります。

ですがご存知の通り、SPA全体をjQueryで組むとひどいことになります。
理由は簡単で、解決すべき問題のデータを、HTMLの構造に直接マッピングできないからです。

さきに書いた通り、情報処理はあるデータをあるデータに変換することです。jQueryは、イベントをうけとり、DOMを操作します。DOMの構造が問題のもつデータの構造と一致しない場合、そのマッピングのため、ひどい操作を強いられます。

JavaScript Template CSS

そこで登場するのがテンプレートエンジンです。テンプレートエンジンは少ない学習コストで、解決すべき問題のデータと、DOMの橋渡しを行います。


<div>私は{{person.name}}です。</div>

ですが、この分割は無用な複雑性を生みます。ぱっとみよさそうですが、なぜでしょう?

データの流れをみる

データはJavaScriptからTemplateに流し込まれます。また、イベントはDOMから発火されます。JavaScriptはDOMの情報を知っている必要があります。
さらに、見た目を更新しないといけない場面も多々あります。よってデータの流れからみる依存関係は、

JavaScript -> Template & CSS

です。ここまでならいいんです。これなら分けたほうがいいです。私も今までここまでしか見えてませんでした。

コードの依存関係を見る

ですが、ちょっと待ってください。コードだってデータです。その依存関係を洗い出す必要があります。
上のテンプレート、よくよく見てみると、 person.name があります。この情報、どこからきたかと考えると、JavaScriptなわけです。
つまり、 JavaScriptのもつ論理構造なしに、テンプレートは存在しえない のです。
ここでコードの依存関係は、こうなります。

Template & CSS -> JavaScript

なんということでしょう、循環参照してしまいました。
凝集性の観点から、一緒にしたほうがいい、という結論になってしまいました。

果たして代替案はあるのか

まず、なぜ分けたいのかを考えると、デザイナがJavaScriptを触れないから、というのが9割くらいだと思います。
よって、要件としては

  • HTML&CSSである

さらに、ヘッダ、フッタ等、複数ファイルで重複すると非常に面倒なことになりますので、

  • Layout、Partialの仕組みがある

さらに、もともとの要件であるので

  • JavaScriptの論理構造に依存しない

なので、こんなのはどうでしょう。


<template id="todo">
  <div class="todo-name">記事を書く</div>
</template>

<template id="todo-list">
  <todo class="todo-items" />
</template>

JavaScript側は


viewmodel: {
  todoItems: [
    {todoName: "記事を書く"}
  ]
}

……うーん。ぱっとみよさそうですが、よくよく考えると微妙感が。でも、だれか作ってそうです。

と本題に関しては終わったので、投げっぱなしで終わります。