gulp
を使って TypeScript なりを変換して SourceMap を使うには gulp-sourcemaps
というモジュールを使います。
それを使えば gulp-typescript
は変換後の *.js
に SourceMap をつけてくれます。しかし、変換前の TypeScript の SourceMap は無視されてしまいます。不便なのでなんとかしてみます。
インストール
multi-stage-sourcemap
という多段 SourceMap のためのモジュールがあるのでそれを使います。 TypeScript の前に実行する変換には gulp-header
を使ってみます。
$ npm install -g gulp
$ npm install -D gulp gulp-header gulp-sourcemaps gulp-typescript multi-stage-sourcemap
加えて、 gulpfile を ES2015 で書くために babel-core
を、node で SourceMap を確認するために source-map-support
を、 gulpfile の中で使うために gulp-util
をそれぞれ入れます。
$ npm install -D babel-core gulp-util source-map-support
コード
SourceMap の確認用に console.trace()
を使ったコードを用意します。
// a.ts
console.trace();
console.trace();
console.trace();
console.trace();
console.trace();
console.trace();
console.trace();
console.trace();
console.trace();
スタックトレースを表示するだけのコードです。
これを変換するための gulpfile が以下です。
// gulpfile.babel.js
import gulp from 'gulp';
import header from 'gulp-header';
import sourcemaps from 'gulp-sourcemaps';
import typescript from 'gulp-typescript';
import multiStageSourcemap from 'multi-stage-sourcemap';
gulp.task('default', () => {
const sourceMaps = new Map();
return gulp.src(['*.ts'])
.pipe(sourcemaps.init())
.pipe(header('//0\n//1\n//2\n' + '\n'.repeat(10000)))
.on('data', (file) => {
const path = file.path.replace(/\.ts$/, '.js');
sourceMaps.set(path, file.sourceMap);
})
.pipe(typescript())
.on('data', (file) => {
file.sourceMap = JSON.parse(multiStageSourcemap.transfer({
fromSourceMap: JSON.stringify(sourceMaps.get(file.path)),
toSourceMap: JSON.stringify(file.sourceMap)
}));
})
.pipe(sourcemaps.write())
.pipe(gulp.dest('.'));
});
gulp.src
で TypeScript を読み込み、 sourcemaps.init
で SourceMap の準備、 header
で先頭にコードを追加、typescript
で変換、 sourcemaps.write
で SourceMap の書き出し、 gulp.dest
で出力をしています。
途中 on('data', ...)
で header
でつけられた SourceMap を記録して、その後 multiStageSourcemap.transfer
でそれと TypeScript によってつけられた SourceMap を合成しています。
実行
実際に変換して、 node
で実行してみます。素の状態だと SourceMap が効かないので require('source-map-support/register');
したあとで変換したコードを読み込みます。
require('source-map-support/register');
require('./a');
変換して実行します。
$ gulp
$ node run.js
Trace
がずらずらと出てきます。 a.js
ではなくちゃんと a.ts
の位置が表示されました。 SourceMap がきちんと効いているようです。
ちなみに .pipe(header('//0\n//1\n//2\n' + '\n'.repeat(10000)))
の + '\n'.repeat(10000)
を消すと 3行目以降の SourceMap がずれました。追加したコードの行数以降にズレが出るようです。どこが原因なのかわからないので 10000 行追加して、 10000 行未満のファイルなら無理やり SourceMap が効くようにしました。バッドノウハウな感じで気持ち悪いですがこれで動くようです。
まとめ
multi-stage-sourcemap
で複数の SourceMap の合成ができる- TypeScript 変換前後の SourceMap を合成すればいい