什麼是源代碼映射?

文篇主要介紹源代碼映射,源代碼映射(Source maps)是以.map結尾的文件,例如example.min.js.mapstyles.css.map。大多數構建工具都可以生成源代碼映射文件,例如 Vite、webpack、Rollup、Parcel、esbuild 等,一些工具默認包含源代碼映射,而其他工具則需要額外的配置才能生成它們。

使用源代碼映射可以方便地在開發過程中進行調試,因爲它們提供了一種將壓縮、混淆和優化的代碼還原爲原始源代碼的方法。這對於診斷和修復錯誤非常有幫助,特別是在生產環境中。源代碼映射還可以幫助你確定哪些代碼行負責執行特定的功能,以及從哪裏調用了特定的函數。

儘管源代碼映射非常有用,但是它們會增加文件大小並增加服務器的負載。因此,在生產環境中通常會禁用它們,而在開發過程中啓用它們以便進行調試。如果你使用的構建工具不支持源代碼映射,則有可能需要手動編寫它們。

下面是正文~~~~

今天,我們要談論源代碼映射,這是現代 Web 開發中非常重要的工具,可以顯著地簡化調試過程。在本文中,我們將探討源代碼映射的基礎知識,它們是如何生成的,以及它們如何提高調試體驗。

需要源代碼映射

回到過去的美好時光,我們使用純 HTML、CSS 和 JavaScript 構建 Web 應用程序,並將相同的文件部署到 Web 上。

然而,隨着我們現在構建更復雜的 Web 應用程序,開發工作流可能涉及使用各種工具。例如:

這些工具需要構建過程將我們的代碼轉換爲標準的 HTML、JavaScript 和 CSS,以便瀏覽器能夠理解。此外,爲了優化性能,通常會壓縮(例如使用 Terser 來縮小和混淆 JavaScript)和合並這些文件,減小它們的大小並使它們更適合於 Web。

例如,使用構建工具,我們可以將以下 TypeScript 文件轉換並壓縮爲一行 JavaScript 代碼。

/* A TypeScript demo: example.ts */

document.querySelector('button')?.addEventListener('click'() ={
  const num: number = Math.floor(Math.random() * 101);
  const greet: string = 'Hello';
  (document.querySelector('p') as HTMLParagraphElement).innerText = `${greet}, you are no. ${num}!`;
  console.log(num);
});

一個壓縮版本將是:

/* A compressed JavaScript version of the TypeScript demo: example.min.js  */

document.querySelector("button")?.addEventListener("click",(()=>{const e=Math.floor(101*Math.random());document.querySelector("p").innerText=`Hello, you are no. ${e}!`,console.log(e)}));

然而,這種優化可能會使調試變得更具挑戰性。將所有內容壓縮到單行中並縮短變量名稱的壓縮代碼可能會使問題的源頭難以確定。這就是源映射的作用——它們將編譯後的代碼映射回原始代碼。

生成源代碼映射

源映射是以 .map 結尾的文件(例如, example.min.js.map 和 styles.css.map )。它們可以由大多數構建工具生成,例如 Vite、webpack、Rollup、Parcel、esbuild 等等。

一些工具默認包含源代碼映射,而其他一些工具可能需要額外的配置才能生成它們。

/* Example configuration: vite.config.js */
/* https://vitejs.dev/config/ */

export default defineConfig({
  build: {
    sourcemap: true, // enable production source maps
  },
  css: {
    devSourcemap: true // enable CSS source maps during development
  }
})

理解源代碼映射

這些源映射文件包含有關編譯代碼如何映射到原始代碼的基本信息,使開發人員能夠輕鬆調試。這是一個源映射的示例。

{
  "mappings""AAAAA,SAASC,cAAc,WAAWC, ...",
  "sources"["src/script.ts"],
  "sourcesContent"["document.querySelector('button')..."],
  "names"["document","querySelector", ...],
  "version": 3,
  "file""example.min.js.map"
}

源映射的最關鍵方面是 mappings 字段。它使用 VLQ 基於 64 編碼的字符串將編譯文件中的行和位置映射到相應的原始文件。可以使用源映射可視化工具(如 source-map-visualizationSource Map Visualization)來可視化此映射。

左側生成的列顯示壓縮內容,右側原始列顯示原始來源。可視化工具會爲原始列中的每一行和生成列中對應的代碼進行着色編碼。

映射部分顯示了代碼的解碼映射。例如,條目 65-> 2:2 的意思是:

瀏覽器開發者工具應用這些源映射,幫助我們更快地定位調試問題,直接在瀏覽器中進行。

該圖顯示了瀏覽器開發者工具如何應用源映射,並顯示文件之間的映射關係。

源映射支持擴展。擴展是以 x_ 命名約定開頭的自定義字段。一個例子是由 Chrome DevTools 提出的 x_google_ignoreList 擴展字段。請參閱 x_google_ignoreList 以瞭解這些擴展如何幫助您專注於我們的代碼。

它不完美

在我們的示例中,變量 greet 在構建過程中被優化掉了。該值直接嵌入到最終的字符串輸出中。

在這種情況下,當我們調試代碼時,開發人員工具可能無法推斷和顯示實際值。這不僅是瀏覽器開發人員工具的挑戰,也使代碼監視和分析更加困難。

當然,這是一個可以解決的問題。其中一種方法是像其他編程語言一樣,在源映射中包含範圍信息,以便進行調試。

然而,這需要整個生態系統共同努力改進源映射規範和實現。目前正在積極討論如何通過源映射來提高調試性能。

我們期待着改進源代碼映射,使調試變得更加簡單!

原文:https://web.dev/source-maps/

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/PuzJw_PujK7qzXGgVIaMLQ