webpackやBabel、uglifyjsなどを使ってソースコードを変換している場合、err.stackに含まれるコードの位置に関する情報が変換後のコードの位置になっており、デバッグが難しい。err.stackに含まれる位置の情報をsource mapを使って、元のコードの位置に変換する方法をちょっとだけ調べた。
調べると色々なnpmパッケージが見つかるが、source-map-supportが有名っぽい。
# 検証用ディレクトリ作成
$ mkdir source-map-support-playground
$ cd source-map-support-playground
# 依存関係のインストール
$ yarn add babel-cli babel-preset-flow source-map-support -D
src.js
に無理やりFlowtypeのコードを書き、source-map-support/register
を読み込む。
// src.js
// @flow
require('source-map-support/register');
function throwsError(message: string) {
throw new Error(`ERR: ${message}`);
}
throwsError('hoge');
Babelで変換し、変換後のファイルを実行してみる。
# source mapをつけて変換
$ babel --presets flow src.js --source-maps > lib.js
# 実行
$ node lib.js
/Users/xxxx/xxxx/src.js:5
throw new Error(`ERR: ${message}`);
^
Error: ERR: hoge
at throwsError (/Users/xxxx/xxxx/src.js:5:9)
at Object.<anonymous> (/Users/xxxx/xxxx/src.js:8:1)
at Module._compile (module.js:569:30)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Function.Module.runMain (module.js:605:10)
at startup (bootstrap_node.js:158:16)
at bootstrap_node.js:575:3
変換後のlib.js
ではなく、src.js
の位置で出力されていますね。
実装を見てみると、souce mapから元の位置を取得するのにmozillaのsource-mapを利用して、err.stackの書き換えはv8のStack Trace APIを使っているみたいです(Stack Trace APIについて、以前触れた記事があるので、よかったらどうぞ)。
今回はNode.jsで動かしましたが、Chromeでも動く(v8だから)ようです。Chrome以外ではerr.stackの書き換えはできなそうなので、mozillaのsource-mapを使ってerr.stack取得後に変換すればいけそうです。試していないので、負荷がどれくらいかかるかはわかりませんが。
Node.jsの場合だと、requireを書くだけなので、簡単でよいですね。