Edited at

TypeScript & CoffeeScript & Browserifyによるフロントエンド開発環境

More than 3 years have passed since last update.

この記事の内容は古くなりました、新しい記事はこちらです。

Browserifyの記事が増えてきましたが、

自分でもフロントエンド開発環境を構築してみて、納得のいく構築が出来ましたので公開します。

GitHubへのリンク

2015/03/26追記

独自タグによるalias指定をoptionalに変更し、

require時に相対パス指定か、aliasがある時はalias指定のどちらも使えるように修正しました。


概要

このプロジェクトは、以下の機能を持っています。


  • TypeScript、Browserifyの差分ビルド

  • gulp.watch、Watchifyの変更監視による自動ビルド

  • TypeScript、CoffeeScriptのソースファイルを混在出来る


    • ファイルごとに型が欲しいか、短く書きたいか、で好きな方を選べばいい

    • CoffeeScriptで書いたクラスをTypeScriptでrequireして使う、等

    • ※当然ですが、型チェックをするならTypeScript同士じゃないとダメ



また、独自拡張として以下の対応をしています。

また、gulpのbuildやwatch中にエラーが発生するとエラー通知がされるようにしています。


Usage


  1. npm install

  2. tsd update -s

  3. gulp (watch | build | clean) [--env production]

--env productionオプションを付けると公開用として、無しだと開発用としてbundleファイルを生成します。

生成の際、開発用(オプションなし)だとソースマップ生成を、公開用(オプションあり)だとbundleファイルの圧縮を行います。


ファイル構成

root

├── src - ソース置き場
│ ├── index.html
| └── scripts
├── gulpscripts - gulp用の自作スクリプト
│ ├── ambient-external-module.coffee - ソース内の専用タグ収集(alias、外部モジュール化の補助)
│ ├── error-log.coffee - エラーログ
| ├── grep-sync.coffee - 同期版のgrep
| ├── gulp-callback.coffee - stream内の任意の場所でコールバックを発生させる
| ├── merge-multi-sourcemap.coffee - 多段ソースマップの合成
| ├── notify-error.coffee - エラーのデスクトップ通知
| └── same-path.coffee - 複数のパスから一致する部分の取得
├── gulpfile.coffee - gulpメインスクリプト
├── package.json - nodeパッケージ
└── tsd.json - TypeScript型定義ファイルパッケージ


ソースへのrequire用のalias、ユーザ外部モジュール化について

ソース中に独自タグである


hoge.ts

// TypeScript

/// <ambient-external-module alias="{filename}" />


foo.coffee

# CoffeeScript

###
<ambient-external-module alias="{filename}" />
###


を埋め込むことにより、

gulpscripts/ambient-external-module.coffee

がソース中のタグを収集し、Browserifyにソースを追加する際にrequireメソッドによりaliasが定義されます。


gulpfile.coffee

b.require('lib/path/to/hoge.js', expose: 'hoge')


また、TypeScriptの場合はdts-bundleにより外部モジュール化されsrc_typingsディレクトリ内にユーザ型定義ファイルが作成されるため、


foo.ts

/// <reference path="root/src_typings/tsd.d.ts" />

import Hoge = require('hoge');
Hoge.foo();


という書き方をする事が出来ます。


多段ソースマップの解決について

AltJSからBrowserifyによるbundleファイル生成までの流れは、以下のようになっています。


  • 1.AltJSのトランスパイル


    • hoge.ts -> tsc -> hoge.js & hoge.js.map

    • foo.coffee -> coffee -c -> foo.js & foo.js.map



  • 2.Browserifyによるbundle


    • (hoge.js & hoge.js.map) & (foo.js & foo.js.map) -> Browserify -> bundle.js & bundle.js.map



中間ファイルであるhoge.jsやfoo.jsのそれぞれのソースマップファイルはAltJSとの紐づけ、

生成物であるbundle.jsのソースマップファイルは中間ファイルとの紐づけがされた状態であり、

bundle.jsのソースマップファイルから、AltJSへと直接紐づける必要があります。

紐づけ方法ですが、mozilla/source-mapによりソースマップ内の対応した位置情報をプロットしてみると、

中間ファイルのソースマップファイルであるhoge.js.mapやfoo.js.mapのgeneratedの位置情報と、

生成物のソースマップファイルであるbundle.js.mapのoriginalの位置情報が対になっていると読み取れます。

multi_source_map_prot.png

この対になっている位置情報を基に、AltJSのoriginalの位置情報と、生成物のbundle.jsのgeneratedの位置情報を取り出せれば、多段ソースマップの問題が解決出来る事になります。

この問題を解決するスクリプトgulpscripts/merge-multi-sourcemap.coffeeを作成し、Browserify実行後に走らせることでこの問題を解決しています。

- ※スクリプト内では、さらに細かく紐づけをしています。

- ※browserifyでuglifyによる圧縮後のソースマップに試しましたが、列の位置が微妙にずれる結果となってしまった為、uglifyと併用した場合は上手く動かない可能性があります。


TypeScriptの定義ファイルについて

定義ファイルは、DefinitelyTypedにより公開されているモジュール用とsrcディレクトリ用の2種類があり、srcディレクトリ用の定義ファイルはgulpで自動生成され、また、TypeScriptを編集した際にも自動更新されます。

また、DefinitelyTypedと同様にルート用の定義ファイル(tsd.d.ts)を用意している為、

定義ファイルのreferenceパスはDefinitelyTyped用、srcディレクトリ用それぞれのtsd.d.tsファイルを参照するだけで良いです。



  • DefinitelyTyped用の定義ファイル


    • typings/tsd.d.ts




  • srcディレクトリ用の定義ファイル


    • src_typings/tsd.d.ts




src/scripts/hoge.ts

/// <reference path="../../typings/tsd.d.ts" />

/// <reference path="../../src_typings/tsd.d.ts" />


参考