Source map 想必你們都不陌生。線上的代碼可能是壓縮後的,若是線上有報錯卻只能調試那個代碼多半是個噩夢。所以咱們須要有一個橋樑幫助咱們搭建起源代碼及壓縮後代碼的聯繫,source map 就是起了這個做用。html
如下是 MDN 對於 source map 的解釋:html5
調試原始源代碼會比瀏覽器下載的轉換後的代碼更加容易。 source map 是從已轉換的代碼映射到原始源的文件,使瀏覽器可以重構原始源並在調試器中顯示重建的原始源。webpack
可是不知道各位讀者有沒有對 source map 的原理產生過疑問?筆者列出了四個疑問,不知道各位是否是也存在過這樣的問題:git
接下來的內容會逐步爲讀者解答這四問。github
這個答案確定是不會影響,不然構建相關的優化就確定會涉及到對於 source map 的處理了,畢竟 source map 文件也不小。web
其實 source map 只有在打開 dev tools 的狀況下才會開始下載,相信大部分用戶都不會去打開這個面板,因此這也就不是問題了。json
這時可能會有讀者想說:哎,可是我好像歷來沒有在 Network 裏看到 source map 文件的加載呀?其實這只是瀏覽器隱藏了而已,若是你們使用抓包工具的話就能發如今打開 dev tools 的時候開始下載 source map 了。數組
source map 是存在一個標準的,爲 Google 及 Mozilla 的工程師制定,文檔地址。正是由於存在這份標準,各個打包器及瀏覽器才能生成及使用 source map,不然就亂套了。瀏覽器
各個打包器基本都基於該庫來生成 source map,固然也存在一些魔改的方案,可是標準都是統一的。markdown
經過上面的庫生成出來的 source map 格式大體以下,你們也能夠對比各個打包器的產物,格式及內容大部分都是一致的:
{
version: 3,
file: "min.js",
names: ["bar", "baz", "n"],
sources: ["one.js", "two.js"],
sourceRoot: "http://example.com/www/js/",
mappings: "CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA"
}
複製代碼
接下來筆者介紹下重要字段的做用:
另外大部分應用都是由 webpack 來打包的,可能有些讀者會發現 webpack 的 source map 產出的字段於上面的略微有些不一致。
這是由於 webpack 魔改了一些東西,可是底下仍是基於這個庫實現的,只是變更了一些不涉及核心的字段,具體代碼。
這裏咱們以 webpack 作個實驗,經過 webpack5 對於如下代碼進行打包:
// index.js
const a = 1
console.log(a);
複製代碼
當咱們開啓 source map 選項之後,產物應該爲兩個文件,分別爲 bundle.js
以及 bundle.js.map
。
查看 bundle.js
文件之後咱們會發現代碼中存在這一一段註釋:
console.log(1);
//# sourceMappingURL=bundle.js.map
複製代碼
sourceMappingURL
就是標記了該文件的 source map 地址。
固然除此以外還有別的方式,經過查閱 MDN 文檔 發現還能夠經過 response header 的 SourceMap: <url>
字段來代表。
這是 source map 最核心的功能,也是最涉及知識盲區的一塊內容。
你們應該還記得上文中沒介紹的 mapping
字段吧,接下來咱們就來詳細瞭解這個字段的用處。
咱們仍是以剛纔打包的文件爲例,來看看產出的 source map 長啥樣(去掉了可有可無的):
{
sources:["webpack://webpack-source-demo/./src/index.js"],
names: ['console', 'log'],
mappings: 'AACAA,QAAQC,IADE',
}
複製代碼
首先 mappings
的內容實際上是 Base64 VLQ 的編碼表示。
內容由三部分組成,分別爲:
console.log(a)
就由 console
、log
及 a
三部分組成,因此存在兩個逗號。逗號和分號想必你們沒啥疑問,可是對於這幾個英文內容應該會很困惑。
其實這就是一種壓縮數字內容的編碼方式,畢竟源代碼可能很龐大,用數字表示行數及列數的話 source map 文件將也會很龐大,所以選用 Base 64 來表明數字用以減小文件體積。
好比說 A
表明了數字 0,C
表明了數字 1 等等,有興趣的讀者能夠經過該網站瞭解映射關係。
瞭解了這層編碼的映射關係,咱們再來聊聊這一串串英文到底表明了什麼。
其實這每串英文中的字母都表明了一個位置:
sources
字段names
字段裏的索引這時讀者可能有個疑惑,爲啥沒有壓縮代碼的第幾行表示?這是由於壓縮後的代碼就一行,因此只須要表示第幾列就好了。
更新:有讀者詢問 Base64 表達的數字是有上限的,若是須要表示的數字很大的話該怎麼辦。實際上除了每一個分號中的第一串英文是用來表示代碼的第幾行第幾列的絕對位置以外,後面的都是相對於以前的位置來作加減法的。
瞭解完以上知識之後,咱們就來根據上文的內容解析下 AACAA
的具體含義吧,經過該網站咱們能夠知道 AACAA
對應了 [0,0,1,0,0]
,這裏須要注意的是數字都從 0 開始,筆者表述的時候會自動加一,畢竟代碼第零行聽起來怪怪的。
index.js
文件了names
數組中的第一個索引,也就是 console
經過以上的解析,咱們就能知道 console
在源代碼及壓縮文件中的具體位置了。
可是爲何 source map 會知道編譯後的代碼具體在什麼位置呢?這裏就要用到 AST 了。讓咱們打開網站輸入 console.log(a)
後觀察右邊的內容,你應該會發現如圖所示的數據:
由於 source map 是由 AST 產出的,因此咱們能用上 AST 中的這個數據。
通常來講 source map 的應用都是在監控系統中,開發者構建完應用後,經過插件將源代碼及 source map 上傳至平臺中。一旦客戶端上報錯誤後,咱們就能夠經過該庫來還原源代碼的報錯位置(具體 API 看文檔便可),方便開發者快速定位線上問題。
source map 是咱們平常中常常用到的東西,可是直到學習這塊內容的時候才知道竟然涉及到了那麼多的知識盲區。
你們若是有什麼疑問歡迎在評論區交流。