sourceMap是個啥

爲啥用sourceMap

這幾天在搞前端錯誤日誌,作過線上發佈的都知道,咱們發佈到生產環境的代碼,通常都有以下步驟:javascript

  • 壓縮混淆,減少體積
  • 多個文件合併,減小HTTP請求數
  • 經過編譯或者轉譯,將其餘語言編譯成JavaScript

這三個步驟,都使得實際運行的代碼不一樣於開發代碼,不論是 debug 仍是捕獲線上的報錯,都會變得困難重重。html

解決這個問題的方法,就是使用sourceMap前端

啥是sourceMap

簡單說,sourceMap就是一個文件,裏面儲存着位置信息。java

仔細點說,這個文件裏保存的,是轉換後代碼的位置,和對應的轉換前的位置。webpack

有了它,出錯的時候,經過斷點工具能夠直接顯示原始代碼,而不是轉換後的代碼。web

sourceMap長啥樣

經過webpack等工具,咱們可使用 sourceMap,這裏不細說配置方法,能夠看這裏數組

sourceMap是一個map文件,與源碼在同一個目錄下。app

在壓縮代碼的最後一行,會有這樣的一個引用:工具

//# sourceMappingURL=app.js.map

指向的就是咱們的map文件。優化

sourceMap的格式以下:

{
    version : 3, //SourceMap的版本,目前爲3
    sources: ["foo.js", "bar.js"], //轉換前的文件,該項是一個數組,表示可能存在多個文件合併
    names: ["src", "maps", "are", "fun"], //轉換前的全部變量名和屬性名
    mappings: "AACvB,gBAAgB,EAAE;AAClB;", //記錄位置信息的字符串
    file: "out.js", //轉換後的文件名
    sourcesContent: " \t// The module cache\n", //轉換後的代碼
    sourceRoot : "" //轉換前的文件所在的目錄。若是與轉換前的文件在同一目錄,該項爲空
}

其餘的都很好解釋,咱們詳細說一下mappings屬性。

mappings

"AACvB,gBAAgB,EAAE;AAClB;"爲例:

  • 每一個分號對應轉換後源碼的一行;
  • 每一個逗號對應轉換後源碼的一個位置;
  • AACvB表明該位置轉換前的源碼位置,以VLQ編碼表示;

位置對應的原理

位置關係的保存經歷了諸多步驟和優化,這個不詳細說了,想看的能夠看這裏,咱們只說最後的結果。

在每一個位置中:

  • 第一位,表示這個位置在【轉換後代碼】的第幾列。
  • 第二位,表示這個位置屬於【sources屬性】中的哪個文件。
  • 第三位,表示這個位置屬於【轉換前代碼】的第幾行。
  • 第四位,表示這個位置屬於【轉換前代碼】的第幾列。
  • 第五位,表示這個位置屬於【names屬性】的哪個變量。

舉例

假設如今有a.js,內容爲feel the force,處理後爲b.js,內容爲the force feel

the爲例,它在輸出中的位置是(0,0),a.jssources的第1個(這裏只是舉例),輸入中的位置是(0,5),thenames的第2個(這裏只是舉例)。

那麼映射關係爲:
0 1 0 5 2

最後將 01052 表示爲 Base64 VLQ 便可。

說明:

  • 全部的值都是以0做爲基數
  • 第五位不是必需的,若是該位置沒有對應names屬性中的變量,能夠省略第五位
  • 每一位都採用VLQ編碼表示,因爲VLQ編碼是可變長的,因此每一位能夠由多個字符構成
  • 爲何不保存轉換後代碼的行號,由於咱們輸出的文件老是一行,這樣輸出的行號就能夠省略,由於都是0,不必寫出來
  • 對於輸出後的位置來講,到後邊會發現它的列號特別大,爲了不這個問題,採用相對位置進行描述

相對位置是啥呢,看示意圖:

第一次記錄的輸入位置和輸出位置是絕對的,日後的輸入位置和輸出位置都是相對上一次的位置移動了多少,例如the的輸出位置爲(0,-10),由於thefeel的左邊數10下才能到這個位置。

VLQ編碼

VLQVariable-length quantity 的縮寫,是一種通用的、使用任意位數的二進制來表示一個任意大的數字的一種編碼方式。這種編碼最先用於MIDI文件,後來被多種格式採用,它的特色就是能夠很是精簡地表示很大的數值,用來節省空間。

這種編碼須要用最高位表示連續性,若是是1,表明這組字節後面的一組字節也屬於同一個數;若是是0,表示該數值到這就結束了。

這樣乾巴巴說不太容易懂,仍是舉個栗子說明一下吧。

如何對數值137進行VLQ編碼:

步驟 結果
將137改寫成二進制形式 10001001
七位一組作分組,不足的補0 0000001 0001001
最後一組開頭補0,其他補1 10000001 00001001

因此,137的VLQ編碼形式爲10000001 00001001

Base64 VLQ

與通常的VLQ的區別:

  • 一個Base64字符只能表示 6bit(2^6)的數據
  • Base64 VLQ須要可以表示負數,因而用最後一位來做爲符號標誌位。
  • 因爲只能用6位進行存儲,而第一位表示是否連續的標誌,最後一位表示正數/負數。中間只有4位,所以一個單元表示的範圍爲[-15,15],若是超過了就要用連續標識位了。

表示正負的方式:

  • 若是這組數是某個數值的VLQ編碼的第一組字節,那它的最後一位表明"符號",0爲正,1爲負;
  • 若是不是,這個位沒有特殊含義,被算做數值的一部分。

咱們再來舉個栗子說明下使用方法。

如何對數值137進行Base64 VLQ編碼:

步驟 結果
將137改寫成二進制形式 10001001
127是正數,末位補0 100010010
五位一組作分組,不足的補0 01000 10010
將組倒序排序 10010 01000
最後一組開頭補0,其他補1 110010 001000
轉64進制 y和I

因此 137 經過Base64 VLQ表示爲yl

能夠看出:

  • Base64 VLQ中,編碼順序是從低位到高位
  • 而在VLQ中,編碼順序是從高位到低位

參考文章

相關文章
相關標籤/搜索