[JavaScript] TypeScriptの外部モジュールとBrowserifyとGulpと

2015/08/11

2015/08/20追記
※この記事の書き方はこれまでのTypeScriptの書き方でした。
ES6での外部モジュールの書き方はこちら
>> [JavaScript] ES6の書き方でTypeScriptの外部モジュールしたい

以下元の記事
===============

こんにちは。きんくまです。

TypeScriptには内部モジュールと外部モジュールとあって、自分では今まで内部モジュールで事足りていたのでした。

前に書いた記事
>> [TypeScript] 内部モジュール (Internal Module) の整理の仕方を考える

でも最近仕様が確定されたES6だとreqire使うみたいなんで、そろそろ外部モジュール使う運用にした方がよいのかな?と思い調べてみたというのが今回の記事です。

TypeScriptのModule
>> Modules · Microsoft/TypeScript Wiki

Browserify

ブラウザだとrequire使ったコードがそのままだと動かなそうなので(最新のブラウザは動くかもしれないけど、、。調べてないです)、Browserifyを使って動かすようにします。

>> Browserifyとは

それで、問題なのがTypeScriptをどうやってBrowserifyと関わらせるのか?なんですが、こちらに全て書かれていました。
>> TypeScript + Gulp + Bower + Browserify – David Kudera

tsifyというBrowserifyのプラグインがあるみたいでそれを使えば簡単にできました。便利ですね。
>> tsify – npm

それで、タスクランナーにGulpを使うときはvinyl-source-streamっていうのも必要なようでそれも入れます。
なんでvinyl-source-streamが必要なのかはこちらに書かれていました。
>> gulp と browserify と vinyl の話 – – はてなブログ

それでできたのがこんな感じのgulpfile.jsです。

gulpfile.js

var gulp = require('gulp');
var browserify = require('browserify');
var tsify = require('tsify');
var source = require('vinyl-source-stream');
var uglify = require('gulp-uglify');
var argv = require('yargs').argv;

function buildTypeScript(){
    function handleError(error) { console.error(error.toString()); }
    var debugMode = argv.release ? false : true;
    var bundler = browserify({
            basedir: 'htdocs/src/ts/',
            debug:debugMode
        })
        .add('MyApp.ts')
        .plugin('tsify', {
            noImplicitAny: true,
            declaration:true
        });
    return bundler.bundle()
        .on('error', handleError)
        .pipe(source('my_app.js'))
        .pipe(gulp.dest('htdocs/js'));
}
function minifyJS(){
    return gulp.src('htdocs/js/my_app.js')
        .pipe(uglify())
        .pipe(gulp.dest('htdocs/js'));
}
//debug
gulp.task('ts-debug', buildTypeScript);

gulp.task('ts-release', buildTypeScript);
gulp.task('js-minify', ['ts-release'], minifyJS);

//release
gulp.task('js-release', ['ts-release', 'js-minify']);

ts-debug(デバッグビルド)
・ソースマップあり

ts-release(リリースビルド)
・ソースマップなし
これはそのままだと上のデバッグビルドと同じようになってしまうので、引数をつけます。

gulp ts-release --release

とコマンドを打つかIntelliJ IDEAだとこんな感じにArgumentsのところに書きます

ts-release

yargsっていうのを使えばこの引数を扱えるみたい。
>> javascript – Is it possible to pass a flag to Gulp to have it run tasks in different ways? – Stack Overflow

js-releaseとするとJavaScriptをTypeScriptのリリースビルド(ts-release)のあとに最小化(minify)するようにしました。

TypeScriptのコード

gulpの設定方法がわかったとして、実際のTypeScriptではどう書けばいいんでしょうか?

内部モジュールのときは /// <reference path= をどこかにまとめて書いておけば全部うまくいきました。
外部モジュールのときはどうするのか?上に書いた公式のWikiによると

・定義ファイル .d.ts はこれまで通り /// <reference path= で読み込む
・外部モジュールは import xxx = require(‘xxx’); で読み込む
・書き出すときは export xxx 形式か export = で書き出す

みたいな感じでした。

ClassA.ts

/// <reference path="../../defs/backbone.d.ts" />
export class ClassA {
    constructor(){

    }
}

を読み込むときはこんな感じにすると読み込めます

import classAfile = require('./ClassA');

var instanceA = new classAfile.ClassA();

ポイントとしては、requireした時点ではclassAfileはファイルの参照であって、その中のClassAまではまだリンクしていないということです。なので、classAfile.ClassAと巡っていく必要があります。
逆に言えば、ClassA.tsはClassAとして書き出されているわけではないので、他のClassなどを書いていくことができます。

ClassB.ts

/// <reference path="../../defs/backbone.d.ts" />
class ClassB {
    constructor(){

    }
}
export = ClassB;

ClassBは最後にexport = 形式で書き出しています。これを使うときはこうなりました。

import ClassB = require('./ClassB');

var instanceB = new ClassB();

ClassBはすでにClassBが直接export = で書き出されているので、ファイルの中身を指定しなくても(ClassB.ClassBのようにしなくても)OKでした。

外部モジュールの感想

毎回ファイルごとにimportとrequireを書くのが思ったよりも面倒です。内部モジュールなら1回どこかに書いておけばおkだったので。
ただECMAの流れとしては外部モジュール使っていくみたいなんで、慣れておいた方が良いという思いもありつつ、内部モジュールで足りてるならまだ内部モジュールでもいいんじゃないのかな?と思ったり。
むー。

LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る