本文 AI 產出,尚未審核

TypeScript 教學:編譯與設定 – compilerOptions.sourceMap


簡介

在前端開發中,除錯是每日必做的工作。當我們使用 TypeScript 撰寫程式碼時,最終會被編譯成 JavaScript,若沒有適當的映射資訊,瀏覽器或 Node.js 只能顯示編譯後的檔案位置,讓除錯變得相當吃力。
compilerOptions.sourceMap 正是為了解決這個問題而設計的,它會在編譯階段產生 .map 檔案,讓開發者在除錯工具(如 Chrome DevTools、VS Code)中仍能看到 原始的 TypeScript 程式碼,並直接在那裡設置斷點、觀察變數。

對於 初學者,source map 能讓學習曲線更平緩;對 中階開發者,則是提升除錯效率、減少定位錯誤時間的必備工具。本文將深入說明 sourceMap 的運作原理、設定方式、常見陷阱與最佳實踐,並提供多個實用範例,幫助你在專案中正確使用它。


核心概念

1. 什麼是 Source Map?

Source Map 本質上是一個 JSON 檔案,描述 編譯後的 JavaScript 行號 與 原始 TypeScript 行號 之間的對應關係。瀏覽器或 IDE 讀取這份檔案後,就能把錯誤堆疊(stack trace)或除錯資訊「還原」回原始檔案。

example.ts   →  tsc →   example.js   +   example.js.map
  • example.js:編譯後的 JavaScript。
  • example.js.map:對應的 Source Map,內含行列映射與原始檔案路徑。

2. 為什麼要開啟 sourceMap?

情境 若未開啟 sourceMap 若開啟 sourceMap
除錯 堆疊只顯示 .js 行號,難以定位 直接在 .ts 檔案中設斷點
錯誤報告 只能看到編譯後的代碼,使用者難以回報 錯誤訊息會指向原始檔案,回報更精確
開發者體驗 需要手動對照編譯前後代碼 IDE 自動映射,省時省力

3. tsconfig.json 中的 sourceMap 設定

在 tsconfig.json 裡,只需要把 sourceMap 設為 true 即可:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist",
    "sourceMap": true          // <─ 開啟 source map
  }
}

小技巧:若同時需要 .d.ts 宣告檔,建議再加上 "declaration": true,讓 IDE 同時取得型別與除錯資訊。

4. 與其他相關設定的關係

設定 影響範圍 與 sourceMap 的互動
inlineSourceMap 把 map 直接寫入 .js 檔案的底部 互斥:若 true,sourceMap 會被忽略
sourceRoot 指定 source map 中的根目錄 常配合 sourceMap 使用,讓路徑更簡潔
mapRoot 指定 map 檔案的輸出目錄 讓產出結構更符合部署需求
removeComments 移除編譯後的註解 不影響 map,但若需要保留原始註解可關閉

程式碼範例

以下示範 4 個常見情境,說明如何在不同環境下使用 sourceMap。

範例 1:最簡單的 tsconfig.json

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2019",
    "module": "esnext",
    "outDir": "build",
    "sourceMap": true   // 開啟 source map
  }
}
# 執行編譯
npx tsc
# 產出
#   build/main.js
#   build/main.js.map

說明:編譯後的 main.js.map 會自動放在同目錄,Chrome DevTools 會自動載入。

範例 2:使用 inlineSourceMap(適合單檔測試)

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "outDir": "dist",
    "inlineSourceMap": true   // 把 map 內嵌到 .js
  }
}
// src/calc.ts
export function add(a: number, b: number): number {
  return a + b; // <-- 想在此處除錯
}
npx tsc
# 產出 dist/calc.js,檔案底部會有
//# sourceMappingURL=data:application/json;base64,....

適用情境:快速測試或在 CI 中不希望產生額外檔案時使用。

範例 3:設定 sourceRoot 讓路徑更乾淨

{
  "compilerOptions": {
    "outDir": "lib",
    "sourceMap": true,
    "sourceRoot": "/src"   // map 中的來源路徑會從 /src 開始
  }
}
// src/utils/logger.ts
export const log = (msg: string) => console.log(`[LOG] ${msg}`);

編譯後的 logger.js.map 會包含:

{
  "version":3,
  "file":"logger.js",
  "sourceRoot":"/src",
  "sources":["utils/logger.ts"],
  ...
}

好處:在部署到 CDN 時,source map 仍能正確指向原始檔案,且不暴露本機絕對路徑。

範例 4:結合 webpack 與 ts-loader 的設定

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.ts',
  mode: 'development',          // 開發模式自動產生 source map
  devtool: 'source-map',        // 告訴 webpack 產生外部 .map 檔
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};
npm run build   # 會產生 dist/bundle.js + dist/bundle.js.map

說明:即使 tsconfig.json 沒有開 sourceMap,只要 webpack 的 devtool 設為 source-map,最終仍會得到完整的映射檔。


常見陷阱與最佳實踐

陷阱 現象 解決方案
忘記同步 sourceMap 與 inlineSourceMap 同時開啟兩者會產生多餘檔案或無法正確載入 僅保留一個,根據需求選擇 true 或 inline
產出目錄與 sourceRoot 不一致 DevTools 顯示 Cannot find source file 確認 sourceRoot 指向正確的相對路徑,或直接省略
在生產環境洩漏原始程式碼 上傳的 .map 檔案被外部下載,暴露商業邏輯 於 CI/CD 階段移除 .map,或在伺服器設定僅允許內部存取
tsc 與其他編譯工具(如 Babel)產生衝突 兩套工具產生不同的 .map,導致混亂 統一使用同一套工具產生 map,或在 babel 中設定 sourceMaps: true 並關閉 tsc 的 sourceMap
未在 IDE 中啟用「自動載入 Source Map」 雖有 .map,但除錯時仍顯示編譯後代碼 在 VS Code 中確認 javascript.debugger.autoAttach 為 on,或在 Chrome DevTools 開啟「Enable JavaScript source maps」

最佳實踐清單

  1. 開發環境:sourceMap: true + sourceRoot(若需要)
  2. 測試環境:可使用 inlineSourceMap 減少檔案數量
  3. 生產環境:不要上傳 .map,或在 CDN 設定 Access-Control-Allow-Origin 為內部 IP
  4. CI/CD:在建置腳本中加入 rm -rf *.map,確保不會意外洩漏
  5. 版本控制:.map 檔案 不 需要加入 Git,使用 .gitignore 排除
# .gitignore
/dist
/*.map

實際應用場景

1. 前端大型單頁應用(SPA)

在 React、Vue 或 Angular 專案中,每個元件 都會被 TypeScript 編譯成獨立的 JavaScript 檔。若沒有 source map,除錯時只能看到壓縮後的代碼,定位錯誤會變成「猜測」的過程。啟用 sourceMap 後,開發者可以直接在元件的 .tsx 或 .vue 檔案內設斷點,快速定位問題。

2. Node.js 後端服務

Node.js 在執行時會載入編譯後的 .js。使用 ts-node-dev 時,內建會產生暫時的 source map;若自行使用 tsc 打包成 Docker 映像檔,建議在 Dockerfile 中保留 *.map,以便在容器內部的遠端除錯(如 VS Code Remote - Containers)時使用。

# Dockerfile 範例
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY tsconfig.json .
COPY src ./src
RUN npm run build   # 產生 .js + .js.map
CMD ["node", "dist/index.js"]

3. 第三方函式庫發佈

若你打算把自製的 TypeScript 函式庫發佈至 npm,建議在 package.json 中同時提供 .d.ts 與 .js.map。使用者在除錯時能直接看到原始的 TypeScript 實作,提升套件的可維護性與開發者體驗。

// package.json
{
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": [
    "dist/**/*.js",
    "dist/**/*.d.ts",
    "dist/**/*.map"
  ]
}

總結

  • compilerOptions.sourceMap 是 TypeScript 提供的除錯利器,讓編譯後的 JavaScript 能映射回原始的 TypeScript 檔案。
  • 正確的 設定(sourceMap: true、sourceRoot、mapRoot)可以讓除錯工具即時顯示原始代碼,提升開發效率。
  • 在 開發、測試與生產 三個階段,應依需求選擇 sourceMap、inlineSourceMap 或完全關閉,以兼顧除錯便利與安全性。
  • 常見的 陷阱 包括設定衝突、路徑不一致以及生產環境意外洩漏原始程式碼;遵循最佳實踐(如 .gitignore、CI/CD 移除 map)即可避免。
  • 無論是 SPA 前端、Node.js 後端,或是 npm 套件,source map 都是提升開發者體驗與維護品質的關鍵工具。

把 sourceMap 加入你的 TypeScript 專案,讓每一次的除錯都變得 清晰、快速且安全!祝你寫程式寫得開心、除錯寫得順利 🚀.