この記事の内容は古くなりました、新しい記事はこちらです。
Browserifyの記事が増えてきましたが、
自分でもフロントエンド開発環境を構築してみて、納得のいく構築が出来ましたので公開します。
2015/03/26追記
独自タグによるalias指定をoptionalに変更し、
require時に相対パス指定か、aliasがある時はalias指定のどちらも使えるように修正しました。
概要
このプロジェクトは、以下の機能を持っています。
- TypeScript、Browserifyの差分ビルド
- gulp.watch、Watchifyの変更監視による自動ビルド
- TypeScript、CoffeeScriptのソースファイルを混在出来る
- ファイルごとに型が欲しいか、短く書きたいか、で好きな方を選べばいい
- CoffeeScriptで書いたクラスをTypeScriptでrequireして使う、等
- ※当然ですが、型チェックをするならTypeScript同士じゃないとダメ
また、独自拡張として以下の対応をしています。
- require時にaliasを指定出来る
- require('alias名')
- (追記)従来のrequire('相対パス')指定も出来る
- TypeScriptにて、ユーザ外部モジュール及び型定義ファイルの自動生成
- import hoge = require(...);
- ソースへのrequire用のalias、ユーザ外部モジュール化について
- 多段ソースマップの問題を解決し、Browserify生成のjsファイル実行中でもAltJSのソースにbreakpointを貼れる
また、gulpのbuildやwatch中にエラーが発生するとエラー通知がされるようにしています。
Usage
- npm install
- tsd update -s
- 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、ユーザ外部モジュール化について
ソース中に独自タグである
// TypeScript
/// <ambient-external-module alias="{filename}" />
# CoffeeScript
###
<ambient-external-module alias="{filename}" />
###
を埋め込むことにより、
gulpscripts/ambient-external-module.coffee
がソース中のタグを収集し、Browserifyにソースを追加する際にrequireメソッドによりaliasが定義されます。
b.require('lib/path/to/hoge.js', expose: 'hoge')
また、TypeScriptの場合はdts-bundleにより外部モジュール化されsrc_typingsディレクトリ内にユーザ型定義ファイルが作成されるため、
/// <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の位置情報が対になっていると読み取れます。
この対になっている位置情報を基に、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
/// <reference path="../../typings/tsd.d.ts" />
/// <reference path="../../src_typings/tsd.d.ts" />