DevTools — 如何在開發者工具上 debug 原始程式碼?

2025年8月11日

💎 加入 E+ 成長計畫 與超過 700+ 位工程師一同在社群成長,並獲得更多深度的軟體前後端學習資源

如何用瀏覽器開發者工具 (DevTools) 定位效能相關問題? 一文中,我們談到可以如何透過瀏覽器的效能 (Performance) 分頁,來定位前端應用程式的效能問題。在這一期主題文中,我們會繼續探討開發者工具 (DevTools) 中的來源(Sources) 面板,讓 debug 變得更有效率、更快完成。

什麼是來源面板 (sources panel)?

相信多數讀者應該對瀏覽器的來源面板不陌生,在開啟瀏覽器的開發者工具後,點擊 Sources 分頁就能夠進到來源面板 (下方是瀏覽 E+ 的 Notion 內容站時,打開來源面板看到的內容)。

來源面板

來源面板顧名思義,是讓開發者可以查看來源的地方。所謂的來源是指程式的原始碼 (source code),因此我們可以在來源面板中檢視各類構築起網站的檔案,包含 JavaScript 的檔案、跟樣式有關的 stylesheet,甚至是各類圖片的資源。

而現代的開發者工具,在來源面板中有提供一些非常有用的方法,能夠讓開發者用更高效的方式 debug。

如何在開發者工具上 debug 原始程式碼?

上一段落提到開發者可以在來源面板中,看到各類構築起網站的資源,然而在現代前端開發中,通常瀏覽器端拿到的程式碼,跟前端開發者最開始寫的程式碼,會看起來不太一樣。

這是因為現代前端框架通常會把程式碼做預處理,所以瀏覽器拿到的程式碼會是處理過後的版本。所以除非是寫純 HTML、CSS、JavaScript,不然前端工程師無法直接在開發者工具的來源面板上 debug。

前端程式碼的預處理有什麼好處與問題?

在往下談之前,相信如果對這塊還不熟的讀者,可能會問說「為什麼前端框架要先做預處理,不把前端工程師寫的原始版本直接給瀏覽器呢?」。

這是因為經過預處理的程式碼,檔案大小會比較小,所以瀏覽器在下載、解析上所需的時間也會比較短。

舉例來說,瀏覽器拿到以下這段程式碼

function a(b) {
  const c = new Date().getFullYear();
  return c - b;
}

上面的程式碼功能與下面這段原始程式碼是一模一樣的

function calculateUserAge(birthYear: number) {
  const currentYear = new Date().getFullYear();
  return currentYear - birthYear;
}

這段原始程式碼,在傳給瀏覽器之前,經過以下的預處理

  • TypeScript 轉譯:因為瀏覽器無法直接處理 TypeScript,所以要先把 TypeScript 程式碼轉成 JavaScript
  • Minified 最小化:原本的程式碼為了維持好的可讀性,在變數命名上會用 calculateUserAge,但是對瀏覽器來說,用 a 的效果也是一樣的,而比起原本的 calculateUserAge,只用 a 所佔用的字元就比較少,也會讓下載與解析比較快

除了轉譯與最小化,前端框架通常也會順便處理打包 (bundling),讓程式碼可以不用一次載那麼多。在這些步驟都完成後,通常程式碼就會變得讓工程師難以閱讀的樣子 (更長一點的程式碼,最終可能轉換成下面這樣讓人無法輕易閱讀的版本)

!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var

雖然說預先轉譯、最小化、打包能帶來好處,但顯然當程式碼到瀏覽器上變這樣,雖然瀏覽器能處理,但人類工程師要 debug 就會變得很困難。

如何 debug 被處理過,導致很難讀的程式碼?

上面談到預處理過的程式碼會很難 debug,那有沒有方法,可以在瀏覽器上也可以看到原始的程式碼呢?

Source map 在這時可以派上用場,根據 MDN 上的解釋 (連結),所謂的 source map 是一個把被處理過的程式碼,對應回原始程式碼的一張表。一般來說會是透過 JSON 的形式來表示。

以 MDN 上的例子來說,假如有個 SCSS 語法如下

ul {
  list-style: none;
  li {
    display: inline;
  }
}

這個 SCSS 語法會被轉換成以下的 CSS

ul {
  list-style: none;
}
ul li {
  display: inline;
}

/*# sourceMappingURL=index.css.map */

這中間的轉換就是透過 index.css.map 這個 source map

{
  "version": 3,
  "sourceRoot": "",
  "sources": ["index.scss"],
  "names": [],
  "mappings": "AAAA;EACC;;AACA;EACC",
  "file": "index.css"
}

上面的這張表,關鍵的點是 mappings 這串有被編碼過的字串,在瀏覽起收到後會解碼,然後就會拿到相關的資訊,讓瀏覽器知道如何對應處理過的程式碼。

具體來說,mappings 中的字串是透過 base64 VLQ 來編碼跟解碼;先前 Svelte 與 Rollup 的原創者 Rich Harris 有一個開源專案 vlq.js (連結),就有展示如何透過 vlq.js 來處理 source map (範例連結),推薦感興趣了解細節的讀者可以看看。

因此針對「在開發者工具的來源面板要如何 debug 原始程式碼」這個問題,只要透過 source map 就能做到。

閱讀更多

以上我們介紹了如何在開發者工具上 debug 原始程式碼?,關於使用瀏覽器的開發者工具,我們在 E+ 成長計畫中的主題文有更深入、實用的探討。

對更深入了解這個主題,以及其他前後端開發、軟體工程、AI 工程主題感興趣的讀者,歡迎加入 E+ 成長計畫一起成長 (連結)。

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們