0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScript の SourceMap を基礎から理解する【仕組み・デバッグ・セキュリティ】

0
Posted at

はじめに

minify されたコードのエラーを見たとき、こんな行番号が出たことはありませんか?

Uncaught TypeError: Cannot read properties of undefined
    at a.b (app.min.js:1:4832)

👉 SourceMap を使えば、圧縮されたコードでも元のファイル・行番号でデバッグできます

この記事では SourceMap の仕組み・デバッグでの使い方・本番運用のリスクを基礎から解説します。


SourceMap とは何か


minify / bundle とは

本番用ビルドでは、コードは次のように変換されます:

【変換前】src/utils.js(読みやすいコード)
function greet(name) {
  const message = `Hello, ${name}!`;
  console.log(message);
}

【変換後】dist/app.min.js(圧縮・難読化)
function greet(n){const m=`Hello, ${n}!`;console.log(m)}

👉 ファイルサイズは小さくなるが、エラーが起きても元のコードがわからなくなる


SourceMap の役割

SourceMap は「変換後のコード」と「変換前のコード」の対応関係を記録したファイルです。

src/utils.js(元コード)
    ↓ build
dist/app.min.js        ← 実際にブラウザが実行するコード
dist/app.min.js.map    ← SourceMap(対応関係の地図)

👉 ブラウザの DevTools がこの .map ファイルを読み込み、元のコードでデバッグできるようにしてくれる


.map ファイルの中身を見てみる

.map ファイルは JSON 形式です。実際に開くと次のような内容です:

{
  "version": 3,
  "file": "app.min.js",
  "sources": ["src/utils.js", "src/main.js"],
  "sourcesContent": ["function greet(name) {...}", "import ..."],
  "names": ["greet", "name", "message"],
  "mappings": "AAAA,SAAS,MAAM,CAAC,IAAI"
}

主要フィールド

フィールド 内容
version SourceMap の仕様バージョン(現在は 3
sources 元ファイルのパス一覧
sourcesContent 元ファイルの内容(インライン埋め込み用)
names 変数名・関数名の一覧
mappings 変換後コードの各位置 → 元コードの位置の対応(VLQ エンコード)

mappings フィールドについて

mappingsVLQ(Variable-Length Quantity) という形式でエンコードされた文字列です。

"AAAA,SAAS,..." → 「変換後の1列目は元ファイルの0行0列目に対応」という情報が圧縮されている

👉 手で読む必要はありません。DevTools や source-map ライブラリが自動で解釈します


ブラウザはどう使うか

ブラウザは変換後のファイルの末尾にある次のコメントを手がかりに .map を取得します:

//# sourceMappingURL=app.min.js.map

👉 このコメントがあると、DevTools が自動的に .map を読み込んで元コードを表示してくれる


デバッグでの使い方


DevTools で元のコードを見る

SourceMap が有効な状態でビルドされたコードをブラウザで開くと、
DevTools の Sources タブに元のファイル構造が表示されます。

Sources タブ
└── webpack://
    └── src/
        ├── utils.js   ← 元のソースコードがここに!
        └── main.js

👉 ブレークポイントも元ファイルの行に貼れる


//# sourceMappingURL の意味

変換後ファイルの末尾に自動挿入されるコメントです:

// 外部ファイルを参照する場合
//# sourceMappingURL=app.min.js.map

// Base64 で .map をインライン埋め込みする場合
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9u...

👉 インライン埋め込みは .map ファイルを別途配置しなくてよいが、ファイルサイズが大きくなる


//# sourceURL との違い

sourceMappingURL sourceURL
用途 ビルド済みコードと元コードのマッピング eval() などで動的に生成したコードに名前を付ける
対象 バンドル後のファイル evalnew Function
// eval したコードに名前を付ける例
eval('function hello() {}' + '\n//# sourceURL=dynamic-module.js');

本番環境でのリスク


❌ SourceMap を本番の公開ディレクトリに置くとどうなるか

//# sourceMappingURL=app.min.js.map があり、かつ .map が公開されていると:

攻撃者がブラウザの DevTools を開く
 → Sources タブに元のソースコードが丸見えになる
 → ビジネスロジック・認証処理・API キーのハードコードなどが露出する

👉 難読化の意味がなくなり、セキュリティ上のリスクになる


✅ 正しい運用パターン3つ

パターン① 本番では SourceMap を生成しない(最もシンプル)

本番ビルド時に SourceMap の出力を無効にする
→ .map ファイルが存在しないのでリスクゼロ
→ デメリット: 本番エラーの調査が難しくなる

パターン② 生成するが非公開ディレクトリに置く

.map ファイルを公開ディレクトリ外に保存する
→ Sentry などのエラートラッキングツールに手動アップロードして活用
→ デメリット: デプロイフローが少し複雑になる

hidden-source-map(webpack)や hidden(Vite)を使うと .map は生成されるが
//# sourceMappingURL コメントが出力されないため、ブラウザから辿られない。

パターン③ 認証が必要な URL に置く

.map ファイルへのアクセスを社内 IP や認証ヘッダーで制限する
→ エンジニアはアクセスできるが外部からは取得できない
→ デメリット: インフラ設定が必要

👉 多くのプロダクションサービスでは パターン①か② が現実的

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?