部署前端之前冠场,開發(fā)者通常會對代碼進行打包壓縮,這樣可以減少代碼大小,從而有效提高訪問速度爵政。然而仅讽,壓縮代碼的報錯信息是很難Debug的,因為它的行號和列號已經(jīng)失真钾挟。這時就需要Source Map來還原真實的出錯位置了洁灵。
為啥變換代碼?
前端代碼越來越復(fù)雜的情況下等龙,開發(fā)者通常會使用webpack处渣、UglifyJS2等工具對代碼進行打包變換,這樣可以減少代碼大小蛛砰,有效提高訪問速度罐栈。關(guān)于變換代碼的原因,這里不妨引用一下大神阮一峰的JavaScript Source Map 詳解:
- 壓縮泥畅,減小體積荠诬。比如jQuery 1.9的源碼,壓縮前是252KB位仁,壓縮后是32KB柑贞。
- 多個文件合并,減少HTTP請求數(shù)聂抢。
- 其他語言編譯成JavaScript钧嘶。最常見的例子就是CoffeeScript。
如何變換代碼琳疏?
下面是一個簡單的“hello World”程序hello.js
function sayHello()
{
var name = "Fundebug";
var greeting = "Hello, " + Name;
console.log(greeting);
}
sayHello();
使用UglifyJS2對源代碼進行壓縮變換:
uglifyjs hello.js \
-m toplevel=true \
-c unused=true,collapse_vars=true \
-o hello.min.js
壓縮后的代碼hello.min.js
function o(){var o="Hello, "+Name;console.log(o)}o();
為啥需要Source Map?
使用Firefox執(zhí)行hello.js的報錯信息是這樣:
ReferenceError: Name is not defined
sayHello file:///Users/fundebug/sourcemap-tutorial/hello.js:4:9
<匿名> file:///Users/fundebug/sourcemap-tutorial/hello.js:8:1
而hello.min.js的報錯信息是這樣:
ReferenceError: Name is not defined
o file:///Users/fundebug/sourcemap-tutorial/hello.min.js:1:18
<匿名> file:///Users/fundebug/sourcemap-tutorial/hello.min.js:1:59
對比壓縮前后的出錯信息有决,我們會發(fā)現(xiàn),錯誤行號和列號已經(jīng)失真空盼,且函數(shù)名也經(jīng)過了變換书幕。而對于真實的前端項目,開發(fā)者會將數(shù)十個源文件壓縮為一個文件揽趾,這時台汇,錯誤的列號可能多達數(shù)千,且出錯的真實文件名也是很難確定的篱瞎,這樣的話苟呐,壓縮代碼的報錯信息是很難Debug的。
而Source Map則可以用于還原真實的出錯位置俐筋,幫助開發(fā)者更快的Debug掠抬。
什么是Source Map?
使用UglifyJS2時指定source-map選項即可生成Source Map:
uglifyjs hello.js \
-m toplevel=true \
-c unused=true,collapse_vars=true \
--source-map hello.min.js.map \
--source-map-include-sources \
--source-map-root \
-o hello.min.js
各種主流前端任務(wù)管理工具,打包工具都支持生成Source Map校哎,具體可以查看生成Source Map - Fundebug文檔。
生成的hello.min.js多了sourceMappingURL,表示Source Map文件的位置闷哆。
function o(){var o="Hello, "+Name;console.log(o)}o();
//# sourceMappingURL=hello.min.js.map
生成的Source Map為hello.min.js.map:
{
"version": 3,
"sources": ["hello.js"],
"names": ["sayHello", "greeting", "Name", "console", "log"],
"mappings": "AAAA,QAASA,KAEL,GACIC,GAAW,UAAYC,IAC3BC,SAAQC,IAAIH,GAGhBD",
"file": "hello.min.js",
"sourceRoot": "",
"sourcesContent": ["function sayHello()\n{\n var name = \"Fundebug\";\n var greeting = \"Hello, \" + Name;\n console.log(greeting);\n}\n\nsayHello();\n"]
}
由hello.min.js.map可知腰奋,Source Map是一個JSON文件,而它包含了代碼轉(zhuǎn)換前后的位置信息抱怔。也就是說劣坊,給定一個轉(zhuǎn)換之后的壓縮代碼的位置,就可以通過Source Map獲取轉(zhuǎn)換之前的代碼位置屈留,反過來也一樣局冰。Source Map各個屬性的含義如下:
- version:Source Map的版本號。
- sources:轉(zhuǎn)換前的文件列表灌危。
- names:轉(zhuǎn)換前的所有變量名和屬性名康二。
- mappings:記錄位置信息的字符串,經(jīng)過編碼勇蝙。
- file:(可選)轉(zhuǎn)換后的文件名沫勿。
- sourceRoot:(可選)轉(zhuǎn)換前的文件所在的目錄。如果與轉(zhuǎn)換前的文件在同一目錄味混,該項為空产雹。
- sourcesContent:(可選)轉(zhuǎn)換前的文件內(nèi)容列表,與sources列表依次對應(yīng)翁锡。
Source Map真正神奇之處在于mappings屬性蔓挖,它記錄了位置是如何對應(yīng)的。JavaScript Source Map 詳解已經(jīng)有很好的解釋馆衔,這里不再贅述瘟判。
怎樣使用Source Map?
主流瀏覽器均支持Source Map功能,不過Chrome與Firefox需要一些簡單的配置哈踱,具體步驟請參考How to enable source maps荒适。下面以MacBook上的Chrome瀏覽器為例,介紹一下配置方法:
1. 開啟開發(fā)者工具
使用快捷鍵option + command + i开镣;或者在菜單欄選擇視圖->開發(fā)者->開發(fā)者工具
2. 打開設(shè)置
使用快捷鍵fn + F1刀诬;或者點擊右上角的三個點的圖標(biāo),選擇Settings
3. 開啟Source Map
在Sources中邪财,選中Enable JavaScript source maps
為了測試陕壹,我寫了一個簡單的HTML文件hello.min.html
<head>
<script type="text/javascript" src="hello.min.js"></script>
</head>
使用Chrome打開hello.min.html,在控制臺看到的錯誤如下:
Uncaught ReferenceError: Name is not defined
at o (hello.min.js:1)
at hello.min.js:1
報錯的文件仍然為hello.min.js树埠,需要刷新一下Source Map才有作用:
Uncaught ReferenceError: Name is not defined
at o (hello.js:4)
at hello.js:8
注意糠馆,Chrome的報錯信息沒有列號,因此4為錯誤的行號怎憋。Chrome不僅可以通過Source Map還原真實的出錯位置又碌,還可以根據(jù)Source Map的sourcesContent還原出錯的源代碼九昧。點擊出錯位置,即可跳轉(zhuǎn)到源碼毕匀,這樣Debug將非常方便铸鹰。
參考鏈接
關(guān)于Fundebug
Fundebug專注于JavaScript、微信小程序皂岔、微信小游戲蹋笼、支付寶小程序、React Native躁垛、Node.js和Java實時BUG監(jiān)控剖毯。 自從2016年雙十一正式上線,F(xiàn)undebug累計處理了6億+錯誤事件教馆,得到了Google逊谋、360、金山軟件等眾多知名用戶的認可活玲。歡迎免費試用涣狗!
版權(quán)聲明
轉(zhuǎn)載時請注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2017/03/13/sourcemap-tutorial/