Webfunny知識分享:webpack sourceMap解析源碼

前端的業務越來越龐大,導致我們需要引入的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反向定位生產環境的源碼位置,就講解完了,你學會了嗎。