在個人博客A debugging issue caused by source code mapping裏我介紹了在我作SAP C4C開發時遇到的一個曾經困擾我好久的問題,最後結論是這個問題因爲JavaScript的source code map機制在Chrome開發者工具裏起做用,實際上是working as designed的一種行爲。可是當時由於時間限制,沒有去深刻學習JavaScript source code map的更多細節。javascript
在這篇文章裏我用一個簡單的UI5應用來研究該機制。這個應用的UI僅僅包含一個Button,點擊以後彈出一個Message Toast。html
下面是我XML view和Controller的實現。html5
打開Chrome開發者工具裏的source code map開關:java
而後瀏覽器裏訪問這個UI5應用,咱們就能在Chrome開發者工具裏看到這些UI5庫文件的調試版本(.dbg.js)。可是在Chrome開發者工具的Network標籤裏,咱們觀察不到這些調試版本文件的加載。那麼問題來了:這些.dbg.js文件從哪裏來的?git
當關閉Chrome開發者工具的source code map功能以後,咱們在Chrome開發者工具裏再也觀察不到這些.dbg.js文件了。將下圖和source code map打開時的截圖作比較:github
單擊sap-ui-core.js,在其最後一行1875行,看到該行內容:chrome
//# sourceMappingURL=sap-ui-core.js.map
這個文件的後綴.map給了咱們提示:其做用就是維護位置映射關係,將sap-ui-core.js(壓縮以後的文件)裏的代碼位置映射到壓縮以前的代碼位置(來自壓縮以前的文件名,代碼行數,代碼列數,涉及到的壓縮以前的JavaScript變量名)。數組
可是,一樣的,我在開發者工具的Network標籤裏也觀察不到這個.map文件被加載。瀏覽器
在Chrome裏輸入url: "chrome://net-internals/#events", 結果顯示確實有一個url請求去訪問sap-ui-core.js.map, 只是由於本地磁盤緩存能響應該請求, 所以沒有產生真正的網絡請求:緩存
在Chrome裏輸入"chrome://cache"能看到Chrome本地的全部緩存,從這裏我成功找到了文件sap-ui-core.js.map的本地緩存。
單擊該超連接能看到這條緩存的擡頭信息。可是緩存的具體文件內容顯示格式爲HEX,無法直接分析。
所以我使用了工具Cache viewer for Google Chrome Web browser, 將該緩存導出成本地文件。
這篇博客Introduction to JavaScript Source Maps介紹了JavaScript source code map的基本知識。
文件sap-ui-core.js.map的內容:
.map文件的各組成部分的做用和含義定義在一個叫作Source Map Revision Proposal的協議文檔裏,在個人例子sap-ui-core.js.map裏使用了該協議的第三版。
這是一個數組,包含了全部用於生成壓縮以後的js文件的原始文件的名稱。
這是一個數組,包含了原始js文件裏出現的JavaScript變量和屬性名稱。
下面是一個例子,體現了原始文件之一Device-dbg.js裏的變量名稱和其在sap-ui-core.js.map文件裏的names數組裏的對應記錄,方便您理解。
.map文件最重要的部分,定義了原始文件內的位置和生成壓縮版本文件內位置的對應關係。對應關係記錄的粒度是基於壓縮以後文件的每一行,用分號隔開。這樣作的好處是無需再分配而外的位來維護壓縮文件位置的行號信息。
回到個人例子,壓縮文件sap-ui-core.js一共包含1874行,所以sap-ui-core.js.map一共出現了1874次分號,每一個分號內又是一個很長的字符串,由一系列逗號隔開,這些由逗號隔開的字符串片斷稱爲Segment。每一個Segment維護了一個位置的映射關係。
有不少開源的組件用於生成.map文件,其中之一是Google Closure compiler。假設我想基於個人測試應用裏的controller實現文件App.controller.js生成一個壓縮版本的文件:
從Google網站下載compile.jar, 而後生成一個名爲script-min.js的壓縮文件和script-min.js.map:
java -jar compile.jar --js App.controller.js --create_source_map ./script-min.js.map --source_map_format=V3 --js_output_file script-min.js
生成的壓縮文件script-min.js只有1行內容:
生成的script-min.js.map內容:
可使用vlq.js將這些segment解碼:
瀏覽器打開該html,產生以下輸出:每一個segment由4或5個字符組成。
每一位的對應含義:
第一位,表示這個位置在轉換後的壓縮文件的第幾列。
第二位,sources數組中的索引,表示這個位置來自哪個原始文件。
第三位,表示這個位置屬於原始文件的第幾行。
第四位,表示這個位置屬於原始文件的第幾列。
第五位,names數組中的索引,表示這個位置屬於源文件中的哪個變量。
關於VLQ編碼的更多細節,能夠閱讀這篇博客Source Maps under the hood – VLQ, Base64 and Yoda
要獲取更多Jerry的原創技術文章,請關注公衆號"汪子熙"或者掃描下面二維碼: