Posted at

出力ファイル以外を用いずにsourcemapを使う

More than 1 year has passed since last update.


はじめに

 埋もれるよりは晒す方がまだ何かのためになると思ったのでそうしました。


sourcemapとは?

 uglifyやlessなど元々のソースを加工して出力するツールがありますが、出力されたファイルを読んでも元のファイルの何行目だとか何列目だとか分かりません。sourcemapを使うことによって元々のファイルのどこに相当するのか分かるようにできます。元のファイルの最終行にまとめて出力したり、x.mapのように別途出力したりタイプは様々です。


趣旨

 sourcemapの対応の仕方はツールによって様々でinline sourcemapに対応していなかったり、変換前のソースがないとsourcemapに何も表示されなかったりします(※1)。下の図みたいな感じですね。真っ白です。

nonExsitOriginal.png

 少し残念なのでsource-mapを用いてsourcemapをアレコレいじり、イカしたsourcemapを作ってやろうぜというのが今回の趣旨です。具体的には以下の条件を満たしたいと思います。


  • 変換前のソースを不要にする

  • x.mapのようなmapファイルを不要にする


source-mapって?

 mozillaが作成しているsourcemapを作成したり編集したりするためのmoduleです。TypeScriptとか一部の方々を除けば大体使っている印象です。デファクトスタンダードと言って問題ないのではないでしょうか。今回のケースでは「SourceMapConsumer、SourceMapGenerator」の2つを理解すれば大丈夫と思われます。


SourceMapConsumer

 JSONからsourcemapオブジェクトを作成する際やsourcemapオブジェクトの情報の取得などに用いる。とりあえず以下みたいな形でsourcemapオブジェクトを生成できると覚えておけば良いと思います。

var sourceMap = require('source-map');

var rawSourceMapJsonData = fs.readFileSync('xx.map', 'utf8'); // 適当にsourcemapの文字列を取得する
var consumer = new sourceMap.SourceMapConsumer(rawSourceMapJsonData);


SourceMapGenerator

 実際にsourcemapを編集したり、sourcemapオブジェクトをJSONに戻したい場合に使用します。上で作ったSourceMapConsumerオブジェクトから以下みたいな形で生成できます。

var generator = sourceMap.SourceMapGenerator.fromSourceMap(consumer);

 以下みたいな形でJSONに戻せます。

var rawSourceMapJsonData = generator.toString();


変換前のソースを不要にする

 sourcemapオブジェクトにsourcesContentの情報を追加してやる必要があります。


  1. SourceMapGeneratorオブジェクトを取得する

  2. SourceMapGeneratorオブジェクトに元のファイルの情報を設定する

  3. JSONに戻す

  4. ファイルに出力する

// 2の処理の具体例(エラーハンドリングとかなし)

consumer.sources.forEach(function(sourcePath) {
var sourceContent = fs.readFileSync(sourcePath, 'utf8');
generator.setSourceContent(sourcePath, sourceContent, 'utf8');
});


x.mapのようなmapファイルを不要にする

 sourcemapオブジェクトをJSONに戻してBase64エンコーディング => 出力後のファイルの最終行に指定のフォーマットで貼り付けみたいなことが必要になります。


  1. 「変換前のソースを不要にする」の3までやる

  2. Base64にエンコードする

  3. 指定のフォーマットのコメントにする

  4. 変換後のファイルの最終行に出力する(下のコード見てください)

// 1から3まで

var base64 = require('base-64');
var utf8 = require('utf8');

var rawSourceMapJsonData = generator.toString();
var base64edSourceMapData = base64.encode(utf8.encode(rawSourceMapJsonData));

/* 以下のコメントを出力ファイルの最終行に貼り付ける
今回はcssだけどjsだと「//# 」とか使う。半角スペースがないと正常に動かないので注意 */

var sourcemapComment = "/*# sourceMappingURL=data:application/json;base64," + rawSourceMapJsonData + " */";

// 出力ファイルだと思ってほしい。以下みたいな感じになる。ソースマップは適当なので動かない

var finalSourceLine = 'にゃーん'; // 出力ファイルの最終行
/*# sourceMappingURL=data:application/json;base64,b3dhYml0bw== */


備考

※1 今時のツールは大体対応しています。じゃあ何故こんな記事を書いたかって? タグを見てください。


参考資料


  • sourcemapの構造についてはこれ