前端的業務越來越龐大,導致我們需要引入的js等靜態資原始檔的體積也越來越大,不得不使用壓縮js檔案的方式來提高載入的效率。
編譯工具的誕生,極大地方便了我們處理js檔案的這一過程,但壓縮後的js檔案極難閱讀,也難以除錯,所以就產生了sourcemap這個功能。
webpack開啟sourcemap功能可以通過壓縮程式碼的堆疊行、列號定位到原始碼的具體位置,我們就以webpack為例來看看如何利用sourcemap反向定位線上原始碼。
SourceMap是一種對映關係。當專案執行後,如果出現錯誤,我們可以利用sourceMap反向定位到原始碼。在chrome瀏覽器裡邊解析當然是非常強大,也非常方便了,但是我們想對線上的壓縮程式碼進行逆向定位,像這樣遠端解析就有些難度了。解析工具就是npm:source-map;
正常的sourceMap配置如下:
const path = require('path'); module.exports = { devtool: 'source-map', // SourceMap的模式(見下表) entry: './src/index.js', // 入口檔案 output: { filename: 'bundle.js', // 檔名 path: path.resolve(__dirname, 'dist') // 資料夾 } }
SourceMap不同模式的特點(見下表)
模式 | 解釋 |
---|---|
eval | 每個module會封裝到 eval 裡包裹起來執行,並且會在末尾追加註釋 //@ sourceURL . |
source-map | 生成一個SourceMap檔案(編譯速度最慢) |
hidden-source-map | 和 source-map 一樣,但不會在 bundle 末尾追加註釋. |
inline-source-map | 生成一個 DataUrl 形式的 SourceMap 檔案. |
eval-source-map | 每個module會通過eval()來執行,並且生成一個DataUrl形式的SourceMap. |
cheap-source-map | 生成一個沒有列資訊(column-mappings)的SourceMaps檔案,不包含loader的 sourcemap(譬如 babel 的 sourcemap) |
cheap-module-source-map | 生成一個沒有列資訊(column-mappings)的SourceMaps檔案,同時 loader 的 sourcemap 也被簡化為只包含對應行的。 |
webpack版本不同,生成source-map的方式也不同,今天我們就以webpack2.0+ 、和webpack4.0+這兩個版本來講講sourcemap的配置和解析,其他版本沒試過,原理相同,心累?。
一、webpack2.0+配置devtool,生成sourceMap
webpack2.0+關於sourceMap的正確配置如下:
const buildConfig = { mode: "production", output: { path: distPath, filename: "./js/[name].[hash].min.js", publicPath: "./" }, plugins: [ new UglifyJSPlugin({ // 1. 這個配置必須 sourceMap: true }), ].concat(baseConfig.htmlArray), devtool: "source-map" // 2. 這個配置必須 }
從webpack的文件上可以看到,只要設定devtool選項就可以了,但是你是無法解析出來,為什麼?因為你生成的sourceMap檔案中,沒有包含sourcesContent這個屬性,所以無法解析出原始碼的內容。
如果你加上 UglifyJSPlugin這個外掛以後,並且配置了sourceMap屬性後,就能夠正常生成帶sourcesContent屬性的.map檔案了。
所以在你想要利用sourceMap反向定位原始碼的時候,就需要保證你的.map檔案包含sourcesContent這個屬性就可以了,我們來看看解析的效果:
就這樣,webpack2.0+版本的sourceMap就可以這樣解析出來了。
二、webpack4.0+配置devtool,生成sourceMap
webpack4.0生成souceMap的方式非常簡單,先去看webpack的官網,文件非常詳細、種類繁多。但是想要通過這些方式對線上壓縮過的js程式碼進行逆向解析,那簡直是不可能。當然,webpack的這個配置也不是為了讓你去解析線上壓縮程式碼的,在瀏覽器的devtool裡解析解析就好了。廢話不多說,進入正題。
第一步、生成生產環境min.js 和 min.js.map檔案
生產版的檔案要壓縮體積,所以必須配置optimization.minimize=true,但是同時也讓mim.js.map檔案失去了sourcesContent屬性,因此無法解析出原始碼了。配置如下:
const buildConfig = { mode: "production", output: { path: distPath, filename: "./js/[name].[hash].min.js", publicPath: "./" }, optimization: { // 1. 這個配置必須 minimize: true }, plugins: [ ].concat(baseConfig.htmlArray), devtool: "source-map" // 2. 這個配置必須 }
第二步、生成本地環境min.js.map檔案
生成本版min.js.map檔案,配置optimization.minimize=true,告訴webpack不壓縮js程式碼,這樣生成的.min.js.map檔案就能夠包含最全面的原始碼,從而能夠反向定位原始碼了。配置如下:
const buildConfig = { mode: "production", output: { path: distPath, filename: "./js/[name].[hash].min.js", publicPath: "./" }, optimization: { // 1. 這個配置必須 minimize: false }, plugins: [ ].concat(baseConfig.htmlArray), devtool: "source-map" // 2. 這個配置必須 }
第三步、解析生產環境min.js.map檔案,獲得本地環境min.js.map檔案的行列號
通過第一次解析生產版的sourceMap檔案,可以得到本地版sourceMap檔案中原始碼的位置,我們得到了新的行列號:A、B。為我們下一次解析做準備。
第四步、根據第三步獲得的新行列號A、B,解析真正的原始碼
將新的行列號A,B代入到本地版的sourceMap檔案中,就可以解析出真正的原始碼位置了,結果如下圖:
因為webpack4.0以上生成和解析sourceMap的步驟相對較為複雜,所以很少能夠在網上找到真正能夠解析成功的文件。
到此,如何利用sourceMap反向定位生產環境的原始碼位置,就講解完了,你學會了嗎。