読者です 読者をやめる 読者になる 読者になる

HTJS: JavaScriptでHTMLを書くとしたら?

AdventCalendar2016 html5 javascript

はじめに

※ この記事は Tech KAYAC Advent Calendar 2016 5日目の記事になります

こんにちは。HTMLファイ部の @butchi_y です。

僕の将来の夢は言語を作ることです。

言語って自然言語かよプログラミング言語かよ、と思われるかもしれませんが、両方です。

「日本語とか英語とか、あんな面倒な言語よく使えたものだな…」と思われるぐらいのものを目指しています。

一方、プログラミング言語としては、自分が普段会話で使っているおしゃべりのように コンピューターに話しかけるだけでプログラミングできるような言語を目指しています。

その一環で、言語や数値表現における究極的な記法を考えており、今回の記事を書くに至りました。

目標

JavaScriptの文法を守った上で(JavaScriptで動くコードで)HTMLを命令ベースで記述することを目指します。

それでいて可読性を損なわず、応用もできればいいなと思いながら書きました。

さまざまな言語でのマークアップ

HTML

こんなHTMLがあったとします。

インデントや改行は統一感があまりないですが恣意的です。

<div>
  <div class="test">
    <h1>ふつうのHTML</h1>
    <p class="content">
      これは
      <a href="http://example.com" target="_blank">アンカー</a>
      の
      <span>テスト</span>
      です。
      <br>
      <span style="color: #f00; font-weight: bold; font-size: 20px;">スタイルも効いた!</span>
      <span>うまくいってよかった!</span>
    </p>
  </div>
</div>

以下がレンダリング結果です。

f:id:butchi_y:20161203180927p:plain

jQuery

jQueryでやるとしたら…

$('<div>')
  .append(
    $('<div>').addClass('test')
      .append($('<h1>').text('HTJS(仮)'))
      .append(
        $('<div>').addClass('content')
          .append('これは')
          .append($('<a>').attr({href: 'http://example.com', target: '_blank'}).text('アンカー'))
          .append('の')
          .append('<br>')
          .append(
            $('<span>').append('テ').append('ス').append('ト')
          )
          .append('です。')
      )
      .append(
        $('<span>')
          .css({
            "color": "#f00",
            "font-weight": "bold",
            "font-size": "20px",
          })
          .append('スタイルも効いた!')
      )
      .append(
        $('<span>').append('うまくいってよかった!')
      )
  )

こんな感じですね。(jQueryのテクニック不足のため、もう少しはいい書き方がありそう。)

これを純粋なJavaScriptのDOM APIでもやろうと思ってましたが、さらに骨が折れそうなので諦めました。

innerHTMLや.htmlメソッドを使えば普通にHTMLを書くだけで済む話ではありますが…。

以下に示す提案手法では、さすがにこれよりは読みやすくなります。

HTJS

ここで提案手法です!

div(
  div({class: "test"})(
    h1("HTJS(仮)"),
    p({class: "content"})(
      "これは",
      a({href: "http://example.com", target: "_blank"})("アンカー"),
      "の",
      span("テスト"),
      "です。",
      br()
    ),
    span({
      style: {
        "color": "#f00",
        "font-weight": "bold",
        "font-size": "20px",
      }
    })("スタイルも効いた!"),
    span("うまくいってよかった!")
  )
)

いかがでしょう。

特徴としては

  • 要素名を関数名として、属性の記述を渡して実行し、返り値の関数に内容を渡して実行すると要素が生成される
  • 属性はオブジェクトとして指定
  • 属性のない要素は2回実行せずともダイレクトに内容を入れられる
  • CSSの記述もjQueryのcssメソッドと同じくオブジェクトで指定

といったところでしょうか。

これを実行できるプログラムは書いたのですが、ちょっと恥ずかしいので気になる方は僕のGitからこっそり探していただくか、こっそりDMください。

Slim・Pug

やっぱりSlimやPugが一番簡潔に書けます。

HTJSから括弧をなくし、属性を Emmet 記法で書くようにしたら、

必然としてほとんどSlimのような記法になりました。

div
  div.test
    h1 Slim
    p.content
      | これは
      a[href="http://example.com" target="_blank"] アンカー
      | の,
      span テスト
      | です。
      br
    span[style="color: #f00; font-weight: bold; font-size: 20px;"] スタイルも効いた!
    span うまくいってよかった!

PugはかつてJadeと呼ばれていた言語です。 属性の書き方がHTMLと似ていないところがSlimに劣ると思ってはいますが、これもかなりのすっきり具合です。

div
  .test
    h1 Pug
    .content
      | これは
      a(href="http://example.com", target="_blank") アンカー
      | の
      span
        | テスト
      | です。
      br
      span(style="color: #f00; font-weight: bold; font-size: 20px;")
        | スタイルも効いた!
      span
        | うまくいってよかった!

HTJSの問題点

HTMLとして用意すべきものは、たった以下の記述だけです。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script src="js/script.js"></script>
  </head>
  <body></body>
</html>

ただ、これが逆に問題なのです。 HTMLに何も情報が書かれていないため、SEOが最悪なのです。 これはAngularJSやReactなどでも問題になっていることだとは思いますが、 SEOだけでなくFacebookにもOGP情報を渡せないので、せめてOGPだけでも設定した方がいいでしょう。

HTJSを応用するなら、動的なDOM更新の用途よりも、Pugのようなコンパイル言語として開発した方が健全に思われます(もちろん両方できればいいのですが)。

記法の改善については、CoffeeScriptと相性がいいかも!?と思いコンバートしてみましたが、思ったようなすっきり感はありませんでした…。

展望

blockやincludeなどのPugの機能をES2015の手助けを借りて実装できたらいいと思ってます。 そしてHTML・CSS・JavaScriptをすべてJavaScriptでやる、となったときに、CSSをどうJavaScriptに落とし込むかも課題です。 また、JavaScriptの体裁から外れてしまうので本末転倒ですが、括弧とインデントの無駄をさらに省いて究極の言語に近づけたいです。


明日はカヤックで唯一な髪型をしている @ryusukefuda さんです。