jsx-linker


jsx-linker というのは、JSXが生成するJavaScriptを後処理して、いろいろごにょごにょするツールです。将来的には他に吸収されて消えてなくなるかもしれないけど、安定するまではガンガン変更できるように独立したツールとして作りました。「コンパイルの後はリンカーだよねjk」ということでlinkerという名前にしたけど、何もリンクはしません。できることは、いろいろな環境用の起動用コードを追加したり、export部を拡張したり、といった感じです。

内部的にはesprimaを使ってJSXコンパイラで生成されたJSをパースして情報を収集し、JSXの出力したJSコードや収集した情報をhogan.jsxのテンプレートに渡すという仕組みになっています。テンプレートを書けばいろんな処理を追加できるようになっています。JSXで --minify をしていても問題なく動くようになっています。

export強化系テンプレート

commonJS, AMD, Closure Compilerに対応したモジュールを生成するテンプレートがそれぞれ用意されています。あとは、小規模開発で、 JSX.require でアクセスするのもめんどいみたいなケースで使えるような「全部Global名前空間に登録」というのもあります。

こんな感じの超絶複雑なロジックが実装されたJSXコードがあったとします。超絶複雑なため、型情報を使って安全にプログラミングできるJSXを使って実装しました。

fib.jsx
__export__ class Fib {
    static function calc(value : int) : int {
        if (value < 3) {
            return 1;
        }
        return Fib.calc(value - 1) + Fib.calc(value - 2);
    }
}

コンパイルして fib.js を作ってみましょう。

$ jsx --release --minify --output fib.js fib.jsx

つぎに、node.jsからこの超絶複雑なロジックを利用できるようにcommonJS形式に変換してみます。

$ npm install -g jsx-linker
$ jsx-linker -t commonjs-lib -o fib-node.js

これで、node.jsからも使えるようになります。

var Fib = require('./fib-node').Fib;

console.log(Fib.calc(10));

JSXの標準入力とくっつけて一行で実行することもできます。

$ jsx --release --minify fib.jsx | jsx-linker --stdin -o fib-node.js

export強化系で使えるテンプレート名は以下のとおりです。

  • commonjs-lib
  • closure-lib
  • amd-lib
  • export-global

イケイケなビルドツールのgrunt-jsxを使っている場合は、 linkerというオプションに commonjs-lib などの文字列を渡すと、jsx-linkerも一緒に実行します。

WebWorker

今後JavaScriptのモジュール化はWebWorkerになっていくという意見もあるように、今後有望なのがWebWorkerでしょう。ただし、Chromeの開発者ツールを使っても値が見られなかったりデバッグが難しいということもあり、JSXで開発すると多くのバグをコンパイル段階で潰せて幸せになれます。それにくわえて、フロントエンドのライブラリがあまり充実していないというJSXの欠点も、WebWorkerでは問題になりません。

先ほど作った超絶複雑なロジックをWebWorker側に持ってきて、ブラウザの負担を軽減しましょう。

fib-worker.jsx
import "js/web.jsx";
import "webworker.jsx";
import "fib.jsx";

class _Main
{
    static function main(argv : string[]) : void
    {
        // called when loading.
    }

    __export__ static function onmessage (event : MessageEvent) : void
    {
        self.postMessage(Fib.calc(event.data as int));
    }
}

このコードをビルドする時は、JSXのプロジェクトをすばやく作る 〜 jsx-initで紹介したjsx-initでWebWorkerプロジェクトを作るのをおすすめします。WebWorkerプロジェクトであれば、$ grunt build でビルドできます。

自前でやる場合は、npmで webworker.jsx をインストールしてください。あとビルド時にwebworker.jsx というファイルが読めるように --add-search-path を追加する必要があると思います。jsx-linkerの -t に渡す文字列は webworker です。

それ以外

ngcore(mainという関数がシステムから呼ばれる→_Main.mainにフォワード)、extjs-app(Ext.deferを使ってExt.jsの初期化が終わったら_Main.mainを起動)がすでにあります。

そのうち、Chrome Appsを追加しようと思っていますが、特定のハンドラがシステムから呼ばれる系はテンプレートをちょっと書くだけですぐに対応できます。

最近はマクロ言語としてJavaScriptやECMAScriptが使われることが多くなっていますが、どのような環境がきてもjsx-linkerがあればJSXが使えるようになります。