Webpack中的sourcemap

Webpack中sourcemap的配置

sourcemap是爲了解決開發代碼與實際運行代碼不一致時幫助咱們debug到原始開發代碼的技術。尤爲是現在前端開發中大部分的代碼都通過編譯,打包等工程化轉換。好比開發環境下用scss寫樣式, 想在瀏覽器中在線編輯css那樣編輯scss就不是那麼容易了。從我本身看過的資料中, sourcemap的概念最先出如今12年, jquer1.9是較早支持sourcemap的庫。這篇博客比較有表明性:Introduction to JavaScript Source Maps,阮一峯的文章JavaScript Source Map 詳解也大量參考該博客。關於sourcemap的原理及做用,基本在這兩篇文章中講清楚了。回到webpack中的sourcemap,就我這幾天的琢磨, 這方面資料相對比較零散,但凡搜索Webpack中sourcemap的配置, 老是能獲得千篇一概的以下信息:
Sourcemap type Quality Notesjavascript

eval: 生成代碼 每一個模塊都被eval執行,而且存在@sourceURLcss

cheap-eval-source-map: 轉換代碼(行內) 每一個模塊被eval執行,而且sourcemap做爲eval的一個dataurlhtml

cheap-module-eval-source-map: 原始代碼(只有行內) 一樣道理,可是更高的質量和更低的性能前端

eval-source-map: 原始代碼 一樣道理,可是最高的質量和最低的性能html5

cheap-source-map: 轉換代碼(行內) 生成的sourcemap沒有列映射,從loaders生成的sourcemap沒有被使用java

cheap-module-source-map: 原始代碼(只有行內) 與上面同樣除了每行特色的從loader中進行映射webpack

source-map: 原始代碼 最好的sourcemap質量有完整的結果,可是會很慢git

webpack中devtool的配置的官方文檔在這 :webpack-devtoolgithub

疑問

反正我看完這些說明是雲裏霧裏, 就我本身而言, 有3個疑問:web

  1. eval和sourcemap有什麼關係,eval模式是sourcemap嗎?

  2. 包含cheap關鍵字的配置中只有行內是什麼意思?

  3. 這幾種不一樣的配置有什麼區別?

解答

看似配置項不少, 其實只是五個關鍵字evalsource-mapcheapmoduleinline的任意組合。這五個關鍵字每一項都表明一個特性, 這四種特性能夠任意組合。它們分別表明如下五種特性(單獨看特性說明有點不明因此,別急,往下看):

  • eval: 使用eval包裹模塊代碼

  • source-map: 產生.map文件

  • cheap: 不包含列信息(關於列信息的解釋下面會有詳細介紹)也不包含loader的sourcemap

  • module: 包含loader的sourcemap(好比jsx to js ,babel的sourcemap)

  • inline: 將.map做爲DataURI嵌入,不單獨生成.map文件(這個配置項比較少見)

瞭解了以上各類不一樣特性, 再來逐一解答以上問題。

eval和sourcemap有什麼關係,eval模式是sourcemap嗎?

evalsource-map都是webpack中devtool的配置選項, eval模式是使用eval將webpack中每一個模塊包裹,而後在模塊末尾添加模塊來源//# souceURL, 依靠souceURL找到原始代碼的位置。包含eval關鍵字的配置項並不單獨產生.map文件(eval模式有點特殊, 它和其餘模式不同的地方是它依靠sourceURL來定位原始代碼, 而其餘全部選項都使用.map文件的方式來定位)。包含source-map關鍵字的配置項都會產生一個.map文件,該文件保存有原始代碼與運行代碼的映射關係, 瀏覽器能夠經過它找到原始代碼的位置。(注:包含inline關鍵字的配置項也會產生.map文件,可是這個map文件是通過base64編碼做爲DataURI嵌入),舉個栗子:eval-source-mapevalsource-map的組合,可知使用eavl語句包括模塊,也產生了.map文件。webpack將.map文件做爲DataURI替換eval模式中末尾的//# souceURL。按照我本身的理解, eval.map文件都是sourcemap實現的不一樣方式,雖然大部分sourcemap的實現是經過產生.map文件, 但並不表示只能經過.map文件實現。下面是eval模式後產生的模塊代碼:

包含cheap關鍵字的配置中只有行內是什麼意思?

這裏的列信息指的是代碼的不包含原始代碼的列信息。 官方文檔對於包含cheap的解釋是這樣的:

> cheap-source-map - A SourceMap without **column-mappings**. SourceMaps > from loaders are not used. 

這句話翻譯過來就是「在cheap-source-map模式下sourcemap不包含列信息,也不包含loaders的sourcemap」這裏的「column-mappings」就是代碼列數的意思,是否包含loaders的sourcemap有什麼區別將在以後提到。debug的時候大部分人都只在乎代碼的行數, 不多關注列數, 列數就是該行代碼從第一個字符開始到定位字符的位置(包括空白字符)包含cheap關鍵字的模式不包含列信息,體如今webpack中就是:若是包含cheap關鍵字,則產生的.map文件不包含列信息。也就是說當你在瀏覽器中點擊該代碼的位置時, 光標只定位到行數,不定位到具體字符位置。而不包含cheap關鍵字時, 點擊控制檯log將會定位到字符位置。

包含列信息後點擊原始代碼的定位,注意光標位置:

不包含列信息的光標位置:

這篇博客:Go to a line number at a specific column直觀地展現了列數的概念。若是深刻到webpack中的細節中體會該配置項,能夠看這篇博客:SurviveJS:Source Maps ,該文章對比了webpack中全部配置項中.map文件的代碼,這裏截取eval-source-mapcheap-source-map的模式產生的.map文件代碼中的mappings字段對比:

devtool: 'eval-source-map'

"mappings": "AAAAA,QAAQC,GAAR,CAAY,aAAZ",

devtool: 'cheap-source-map'

"mappings": "AAAA",

注:這裏使用了VLQ編碼,(關於VLQ編碼還可參考這裏:前端構建:Source Maps詳解) 在VLQ編碼中,逗號,表示字符列分割,分號;表示行分割。包含cheap關鍵字的配置項不包含列信息,也就沒有逗號。關於VLQ編碼, 本文最初的阮一峯的文章中有所解釋。而不包含loader的sourcemap指的是不包含loader的sourcemap,不包含它時候若是你使用了諸如babel等代碼編譯工具時, 定位到的原始代碼將是通過編譯後的代碼位置,而非原始代碼。

好比當我用babel編譯JS的時候,若是包含不包含loaders的sourcemap,此時debug到的將是編譯後的代碼, 而非原始代碼,如圖(這是使用cheap-source-map模式未包含loaders的sourcemap狀況下的截圖, debug的位置與以前的對比截圖是同一個地方):

這幾種不一樣的配置有什麼區別?

經過以上兩個問題的解釋, webpack中的sourcemap各個配置項異同應該有了必定認識,乍看之下各個配置項很難記憶, 但其實從每一個關鍵字所表明的特性入手, 就能體會到他們的異同。他們在webpack中的主要區別一個體如今重構的性能上, 總的來講eval性能最好,source-map性能最低,但就我自身的實踐來看大多用的是最完整的source-map,該模式對於不論是js仍是css,scss等都能很好的覆蓋, 相反其餘模式都不完整, 在開發環境下重構性能彷佛比不上功能的完善。 
另外須要補充的是module關鍵字, 當加上module關鍵字webpack將會添加loader的sourcemap。

相關文章
相關標籤/搜索