TypeScriptのコンパイルだけでBrowserifyを使わずにモジュールファイルを結合したIsomorphicなNPMのパッケージを作る

TypeScript1.8ではモジュールを結合して1つのファイルに出力できるようになり、これによりBrowserifyを使わずにIsomorphicなJavaScriptライブラリを作れるようになります。NPMのパッケージもNodeでもブラウザでもそのまま使える素敵なライブラリが簡単に作れます。これはもうTypeScriptを使うしかありませんね(バージョン1.8から)。

この記事はTypeScript アドベントカレンダー2015 8日目の記事です。

github.com

出力したモジュールファイルを1つのファイルに結合する機能がマージされました。

ただしこの機能はパッケージ名でネームスペースを集約できないようなのでライブラリ開発でそのまま使うことはできません。

パッケージ名でルートのファイルを作ることでネームスペースを区切れるようなのでそこだけ気をつけましょう。

// src/a.ts
export default 1;

// src/b.ts
import a from './a';
export var b = a + 1;

// mylib.ts
import a from './src/a';
import {b} from './src/b';
export default a + b;
console.log(a, b);

これを1つのファイルにコンパイルします。

$ tsc -t es5 -m amd --moduleResolution node --outFile bundle.js mylib.ts src/a.ts src/b.ts

次のように出力されます

// bundle.js
define("src/a", ["require", "exports"], function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = 1;
});
define("src/b", ["require", "exports", "src/a"], function (require, exports, a_1) {
    "use strict";
    exports.b = a_1.default + 1;
});
define("mylib", ["require", "exports", "src/a", "src/b"], function (require, exports, a_2, b_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = a_2.default + b_1.b;
    console.log(a_2.default, b_1.b);
});

このままでは動かないので先頭に以下のコードを追加してブラウザとNodeの両方で動くようにします(Node/Chrome/Firefox/IE9で動作確認済み)。

ソースコードでrequire, exports, moduleを触っているコードには対応していないのでes6 modulesだけ使ってください。

gist.github.com

define関数が定義されていなければブラウザでもNodeと同様に同期的に読み込まれグローバル変数に追加されます。

// node
$ node
> require('./bundle.js')
1 2
{ default: 3 }
// browser
> 1 2
mylib
> { default: 3 }

うまく動きました。

実際にこの方法で作ったクロスプラットフォームで動作するパッケージがこちらです。

github.com

TypeScript1.8がリリースされたらNPMのパッケージはTypeScriptでIsomorphicに作りましょう。