JavaScriptとプリプロセッサ

uupaa.js にはビルドツール(minify/upa.php)が同梱されています。

upa.php

  • C/C++ のように #include src.js を自動的に展開します。
    • クライアントサイド JavaScriptでは include は予約語ではありませんが、(他のライブラリと衝突する可能性があるので)通常はコメントアウトした状態で使います。
// === uu.msgpack / window.msgpack ===
//#include uupaa.js                ← こことか
//#include misc/utf8.js            ← ここ

// MessagePack -> http://msgpack.sourceforge.net/

(this.uu || this).msgpack || (function(namespace) {

   :
   :
  • ドット演算子を含む定数をリテラル値に置換します
    • if (type === uu.type.FUNCTION) {} → if (type === 128) {}
  • 実体が定義されていないAPIの検出と、可能ならば必要なソースコード自動的にincludeします
    • これは uu.hoge.huga() と function uuhogehuga() の対応を調べています
      • 静的な対応を見ているため、fn = uu.hoge.huga; fn(); のように動的な呼び出しは検出できません
  • -mb オプションをつけると、MobileWebKitに不要なクロスブラウザなコードを全てそぎ落とした、WebKit専用のJavaScriptコードを生成します。
    • さらなる最適化も(関数をinline展開したりとか)

Unknown API の検出と、Auto Include の実行例

upa -v ui/slider.js ui/drag.js

<script src="../../src/uupaa.js"></script>
<script src="../../src/ui/slider.js"></script>
<script src="../../src/ui/drag.js"></script>
  AutoInclude - uu.node.normalize()        ← Unknown API 検出 + Auto Include 成功
<script src="../../src/node/normalize.js"></script>
  AutoInclude - uu.image.size()            ← Unknown API 検出 + Auto Include 成功
<script src="../../src/image/image.js"></script>
  UnknownAPI - uu.css.toRelative()        ← Unknown API 検出 + Auto Include 失敗
  UnknownAPI - uu.css.toAbsolute()        ← Unknown API 検出 + Auto Include 失敗
  AutoInclude - uu.ui.dragbase()          ← Unknown API 検出 + Auto Include 成功
<script src="../../src/ui/dragbase.js"></script>
  UnknownAPI - uu.event.more()            ← Unknown API 検出 + Auto Include 失敗
  UnknownAPI - uu.css.size()              ← Unknown API 検出 + Auto Include 失敗
  UnknownAPI - uu.css.size.set()          ← Unknown API 検出 + Auto Include 失敗

↑は、わざと意地悪な状態にして出したものです。

普通に実行すると↓のような結果になります。

<script src="../../src/uupaa.js"></script>
<script src="../../src/ui/slider.js"></script>
<script src="../../src/node/normalize.js"></script>
<script src="../../src/image/image.js"></script>
<script src="../../src/color/color.js"></script>
<script src="../../src/css/text.js"></script>
<script src="../../src/ui/drag.js"></script>
<script src="../../src/css/box.js"></script>
<script src="../../src/ui/dragbase.js"></script>
<script src="../../src/ui/zindex.js"></script>
<script src="../../src/ui/shim.js"></script>
  AutoInclude - uu.ui.zindex.beginDrag()  ← なんだか実体が見つからないよ(でもInclude済みだね)
  AutoInclude - uu.ui.zindex.endDrag()    ← なんだか実体が見つからないよ(でもInclude済みだね)

uu.ui.zindex.beginDrag の実体は ui/zindex.js 内の uu.Class.Zindex.zbegindrag です。
検出er が「実体無いみたいだけど大丈夫?」とあやしんでいますが、既に ui/zindex.js がロード済みなので、最終的に「問題なし」になっています。

ここからが本題だったり

このビルドツール(upa.php)はある程度の汎用性を持っています。
# 他のライブラリのビルドに使ったり、一般的なWebの開発でもちょっと直せば利用可能な感じに

C言語向けのプリプロセッサ(c.pp)となんちゃってstdio.hを用意し、以下のコードを upa -pp c.pp -core c.js としてビルドすると…

//#include <stdio.h>

int main() {
    printf("hello world!");
}

http://pigs.sourceforge.jp/blog/20100604/0.8/hello.htm

JavaScript の良いところは、ビルドが不要ですぐ動くところだ」

おおむね同意だよ。

でも、強力なビルドツールや、プリプロセッサの導入は、JavaScript LIFE を豊かにするよね。
# ネタ的にね!