本文 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 檔案的底部 互斥:若 truesourceMap 會被忽略
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:結合 webpackts-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,只要 webpackdevtool 設為 source-map,最終仍會得到完整的映射檔。


常見陷阱與最佳實踐

陷阱 現象 解決方案
忘記同步 sourceMapinlineSourceMap 同時開啟兩者會產生多餘檔案或無法正確載入 僅保留一個,根據需求選擇 trueinline
產出目錄與 sourceRoot 不一致 DevTools 顯示 Cannot find source file 確認 sourceRoot 指向正確的相對路徑,或直接省略
在生產環境洩漏原始程式碼 上傳的 .map 檔案被外部下載,暴露商業邏輯 於 CI/CD 階段移除 .map,或在伺服器設定僅允許內部存取
tsc 與其他編譯工具(如 Babel)產生衝突 兩套工具產生不同的 .map,導致混亂 統一使用同一套工具產生 map,或在 babel 中設定 sourceMaps: true 並關閉 tscsourceMap
未在 IDE 中啟用「自動載入 Source Map」 雖有 .map,但除錯時仍顯示編譯後代碼 在 VS Code 中確認 javascript.debugger.autoAttachon,或在 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: truesourceRootmapRoot)可以讓除錯工具即時顯示原始代碼,提升開發效率。
  • 開發、測試與生產 三個階段,應依需求選擇 sourceMapinlineSourceMap 或完全關閉,以兼顧除錯便利與安全性。
  • 常見的 陷阱 包括設定衝突、路徑不一致以及生產環境意外洩漏原始程式碼;遵循最佳實踐(如 .gitignore、CI/CD 移除 map)即可避免。
  • 無論是 SPA 前端、Node.js 後端,或是 npm 套件,source map 都是提升開發者體驗與維護品質的關鍵工具。

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