DevTools — 如何在开发者工具上 debug 原始程式码?
2025年8月11日
在 如何用浏览器开发者工具 (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+ 成长计划一起成长 (连结)。