Mithril 1.1.0

JSX


説明

JSXは、JavaScriptの中にHTMLタグを書けるようにする文法拡張です。これはJavaScript標準の一部でもなければ、アプリケーションの構築に必要なわけでもありませんが、チームの好みによっては使用した方が良いでしょう。

var MyComponent = {
  view: function() {
    return m("main", [
      m("h1", "Hello world"),
    ])
  }
}

// 次のように書ける:
var MyComponent = {
  view: function() {
    return (
      <main>
        <h1>Hello world</h1>
      </main>
    )
  }
}

JSXを使うときは、中括弧を使って、JavaScriptの式を中に書くことができます:

var greeting = "Hello"
var url = "http://google.com"
var link = <a href={url}>{greeting + "!"}</a>
// <a href="http://google.com">Hello</a>となる

コンポーネント名の最初の文字を大文字にすることで、コンポーネントも使用できます:

m.render(document.body, <MyComponent />)
// m.render(document.body, m(MyComponent))と同じ

セットアップ

JSXを使用するもっとも簡単な方法は、Babelプラグインを使うことです。

BabelはNode.jsをインストールすると維持でインストールされるnpmが必要です。npmがインストールされたら、プロジェクトフォルダを作り、次のコマンドを入力しましょう:

npm init -y

もしWebPackとBabelを同時に使いたいのであれば、次のセクションまで飛ばしてください。

Babelをスタンドアロンツールとして導入するには次のコマンドを実行します:

npm install babel-cli babel-preset-es2015 babel-plugin-transform-react-jsx --save-dev

.babelrcファイルを作成します:

{
    "presets": ["es2015"],
    "plugins": [
        ["transform-react-jsx", {
            "pragma": "m"
        }]
    ]
}

スタンドアロンツールとしてBabelを実行するには、次のように起動します:

babel src --out-dir bin --source-maps

WebPackとBabelを使用する

もしソースコードのバンドルにWebPackをすでに使っているのであれば、次のように設定することでBabelをWebPackに統合できます。

npm install babel-core babel-loader babel-preset-es2015 babel-plugin-transform-react-jsx --save-dev

.babelrcファイルを作成します:

{
    "presets": ["es2015"],
    "plugins": [
        ["transform-react-jsx", {
            "pragma": "m"
        }]
    ]
}

次に、webpack.config.jsというファイルを作成します

module.exports = {
    entry: './src/index.js',
    output: {
        path: './bin',
        filename: 'app.js',
    },
    module: {
        loaders: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader'
        }]
    }
}

この設定ファイルでは、アプリケーションのエントリポイントがsrc/index.jsにあり、出力先がbin/app.jsにあることを想定しています。

バンドラーを実行するにはnpmスクリプトの設定を行います。package.jsonファイルを開き、"scripts"以下に次のstart節を追加します:

{
    "name": "my-project",
    "scripts": {
        "start": "webpack -d --watch"
    }
}

これでバンドラーをコマンドラインツールから実行できるようになりました:

npm start

本番ビルド

ミニファイされたファイルを生成するには、package.jsonを開き、buildという新しいnpmスクリプトの項目を追加します:

{
    "name": "my-project",
    "scripts": {
        "start": "webpack -d --watch",
        "build": "webpack -p",
    }
}

本番環境ではフックを使ってスクリプトの本番ビルドを自動でビルドさせることができます。次のコードはHerokuを使うサンプルです:

{
    "name": "my-project",
    "scripts": {
        "start": "webpack -d --watch",
        "build": "webpack -p",
        "heroku-postbuild": "webpack -p"
    }
}

JSX vs hyperscript

JSXにはトレードオフがあります。中括弧でコードの入ったHTMLなど、適切なツールなしでは実行できないような非標準の文法でコードを書く必要があります。JSXを使う主なメリットとしては、構文に寛容で問題を特定するのが難しい通常のHTMLとは異なり、JSXの仕様は遥かに厳しく、構文エラーを出してくれる点があります。

HTMLと異なり、JSXは大文字と小文字を区別します。<div className="test"></div>と、すべてが小文字の<div classname="test"></div>が違う意味になります。前者はm("div", {className: "test"})に、後者はm("div", {classname: "test"})となり、後者はクラス属性の指定方法としては正しくありません。幸い、Mithrilは標準のHTML属性名をサポートしているため、このサンプルは通常のHTMLと同じく、<div class="test"></div>と書くことができます。

JSXはJavaScriptの経験があまりないがHTMLを頻繁に書くようなチームには有用です。しかし、JSX環境を維持するために数多くのツールが必要となります。通常のHTMLであればブラウザで開くだけです。

HyperscriptはJSXをコンパイルした後の表現です。すでに他のドキュメントで説明したとおり、Hyperscriptはそのまま読めるようにデザインされており、JSXの代わりに使えるようになっています。次の理由により、HyperscriptはJSXよりもシンプルになる傾向があります:

それに加えて、HyperscriptはプレーンなJavaScriptなので、JSXよりも自然にインデントができます:

//JSX
var BigComponent = {
  activate: function() {/*...*/},
  deactivate: function() {/*...*/},
  update: function() {/*...*/},
  view: function(vnode) {
    return [
      {vnode.attrs.items.map(function(item) {
        return <div>{item.name}</div>
      })}
      <div
        ondragover={this.activate}
        ondragleave={this.deactivate}
        ondragend={this.deactivate}
        ondrop={this.update}
        onblur={this.deactivate}
      ></div>
    ]
  }
}

// hyperscript
var BigComponent = {
  activate: function() {/*...*/},
  deactivate: function() {/*...*/},
  update: function() {/*...*/},
  view: function(vnode) {
    return [
      vnode.attrs.items.map(function(item) {
        return m("div", item.name)
      }),
      m("div", {
        ondragover: this.activate,
        ondragleave: this.deactivate,
        ondragend: this.deactivate,
        ondrop: this.update,
        onblur: this.deactivate,
      })
    ]
  }
}

重要なアプリケーションでは、コンポーネントがマークアップよりも多くの制御フローとコンポーネント設定コードを持つことがあるため、JavaScriptファーストのアプローチの方が、HTMLファーストアプローチよりも読みやすくなります。

言うまでもなく、Hyperscriptは純粋なJavaScriptなので、実行可能なコードを生成するためにコンパイルする必要はありません。


HTMLの変換

Mithrilでは、正しく書かれたHTMLはJSXとしてそのまま使えます。コピーアンドペースト程度の労力を払えば、独立して作られたHTMLファイルを元にしてJSXを使ってプロジェクトに組み込むことができます。

hyperscriptを使う時は、実行前にHTMLからhyperscriptの文法に変換する必要があります。HTML-to-Mithrilテンプレートコンバーターを使って変換できます。


License: MIT. © Leo Horie.