Rollupでsourcemapの出力場所を変えたい
無理でした
モチベーション
モチベーションはSentryへのアップロード。
実行ファイルはS3にアップロードしてソースマップは隠したい。
実行ファイルとソースマップをSentryへアップロードしてSentry上ではソースを見られるようにしたい。
dist/public/xxx.js
dist/sourcemap/xxx.js.map
のように別れていれば、S3へはdist/public
を、Sentryへはdist/public
とdist/sourcemap
をアップロードするだけでいいため。
解決策
- 実行ファイルとソースマップを一箇所に出力して、mvコマンドで移動する。
- 実行ファイルとソースマップを一箇所に出力して、S3へのアップロード時にソースマップを除外する。
それぞれ//# sourceMappingURL=index.be4ea714.js.map
のようなリファレンスコメントをどうするか(残すか消すか)問題は残る。
- 消さない。
- S3へのアップロード時だけ消す。
- S3とSentryどちらのアップロード時にも消す。いわゆる
hidden
ソースマップ。
消さない。
メリット
- 簡単。
デメリット
- ブラウザーの開発者ツールに、ソースマップが404であるとワーニングが大量に出てうるさい。
S3へのアップロード時だけ消す。
メリット
- Sentryのソースマップ紐付けがうまくいきやすい。標準的な方法かつ現プロジェクトで実績ありのため。
- ブラウザーの開発者ツールにワーニングが出ない。
デメリット
- S3とSentryのアップロードに順序性が生じたり、S3のアップロードにカスタムロジックが混じったりする。
順序性。
Sentryにアップロード後sourceMappingURL
コメントを消してS3にアップロードするとなると、アップロード順序を逆にはできないということ。
カスタムロジック。
ローカルのディレクトリとS3のバケットをただ同期するだけ、といったシンプルなロジックでは対応できない。
特定拡張子のファイルを除外する、くらいだったらまだ汎用的だと言い張れるが、ファイル末尾の特定コメントを削ぎ落としてアップロードとなると厳しい。
これらのデメリットは、S3用とSentry用のアップロードファイルを別の場所に置けば解決はする。
hidden
ソースマップ。
S3とSentryどちらのアップロード時にも消す。いわゆるメリット
- シンプル。S3とSentryどちらにも同じ実行ファイルをアップロードしているのでわかりやすい。
- ブラウザーの開発者ツールにワーニングが出ない。
デメリット
- Sentryがソースマップ紐付けをしてくれない可能性がある。
SentryはsourceMappingURL
コメントもしくはSourcemap
ヘッダー(実行ファイルのHTTPレスポンスヘッダーのことだと思う)を見てソースマップを探すので、コメントを消すとなるとSourcemap
ヘッダー一択となる。
ただ、ファイルの中身に特定のコメントが書いてあるかと、特定のヘッダーが返ってきているかだと、デバッグは前者が楽。
Sourcemap
ヘッダーはどう付与されるのだろうか
sentry-cli sourcemaps upload --help
コマンドの結果を見ると、気になるオプションがあった。
--no-sourcemap-reference
Disable emitting of automatic sourcemap references.
By default the tool will store a 'Sourcemap' header with minified files so that
sourcemaps are located automatically if the tool can detect a link. If this causes
issues it can be disabled.
sentry-cliはデフォルトでSourcemap
ヘッダーを保存する。
それが困るならこのオプションで無効にできる。
つまり、Sourcemap
ヘッダーはsentry-cliがアップロード時に付与してくれるようだ。
その処理を追えばSourcemap
ヘッダー方式がうまくいくかわかるかもしれない。
sentry-cliのソースコードを読むぞ
Rust!
雰囲気で読む!
-
no-sourcemap-reference
でgrep。
-
no_sourcemap_reference
でgrep。
-
add_sourcemap_references
を見つける。
source.ty != SourceFileType::MinifiedSource
でないならguess_sourcemap_reference
をしてくれるらしい。
推測(ファイルが実在するか見るようだから「探索」かな)パターンは4つ。
// foo.min.js -> foo.map
// foo.min.js -> foo.min.js.map
// foo.min.js -> foo.js.map
// foo.min.js -> foo.min.map
cf. fn guess_sourcemap_reference(sourcemaps: &HashSet<String>, min_url: &str) -> Result<String> {
実行ファイル名はどうしても*.min.js
でないといけない雰囲気がある。
source.ty
を決定するのは次の箇所のようだ。if式だ。
is_ram_bundle_slice
やis_hermes_bytecode
など見慣れない名前の判定関数が見えるが、これはReact Native関係のようなので、WebにJSファイルをアップロードするだけの今回は関係ないだろう。
するとこの条件がsource.ty == SourceFileType::MinifiedSource
にする(そしてguess_sourcemap_reference
をする)ための条件となる。
is_likely_minified_js
はmight-be-minified
というライブラリーのメソッドで、中身は次のようになっている。
よくわからない。
ファイルの中身をなんとかしてsource.ty == SourceFileType::MinifiedSource
判定を得るのは難しそうだ。
誤判定もあるし、判定ロジックも変わりうる。
つまりx.contains(".min.")
、実行ファイルのファイル名が.min.
を含むかで判定をもらうしかない。
Sourcemap
ヘッダーをsentry-cliにつけてほしかったら、実行ファイルはfoo.min.js
としろということだ。
この方の実験結果とも一致した。