一直以來(lái)對(duì)source map 都懵懵懂懂, 被webpack 所提供的多樣的source 給亂花了眼。 這次就決定來(lái)一一嘗試一下各種source map的區(qū)別
什么是source map
現(xiàn)代的前端開(kāi)發(fā)總是伴隨的各種框架, 在使用這些框架開(kāi)發(fā)的代碼需要經(jīng)過(guò)編譯才可以在生產(chǎn)環(huán)節(jié)使用, 編譯后就伴隨著可讀性的降低,也會(huì)影響我們的錯(cuò)誤調(diào)試。
那source map就是為了解決這個(gè)問(wèn)題。
Source map可以理解為一個(gè)地圖, 通過(guò)它可以獲知編譯后的代碼 對(duì)應(yīng)編譯前的代碼位置。這樣當(dāng)代碼遇到異常, 我們就可以通過(guò)報(bào)錯(cuò)信息定位至準(zhǔn)確的位置。 同時(shí)在瀏覽器 sources 也可以查看到源碼。
編譯后的代碼內(nèi)只需要包含這樣一句
// @ sourceMappingURL=map文件路徑
就可以關(guān)聯(lián)上 source map文件了
devtool
webpack 通過(guò) devtool 控制需要生成的 source map 類(lèi)型
我們來(lái)看一下 devtool 的支持的屬性devtool, 可以看到 source map 同時(shí)也分為很多種,但大體上都是加載形式的區(qū)別, 本質(zhì)的核心還是相同的。
把它們羅列出來(lái)居然有這么多
- eval
- eval-cheap-source-map
- eval-cheap-module-source-map
- eval-source-map
- cheap-source-map
- cheap-module-source-map
- source-map
- inline-cheap-source-map
- inline-cheap-module-source-map
- inline-source-map
- eval-nosources-cheap-source-map
- eval-nosources-cheap-module-source-map
- eval-nosources-source-map
- inline-nosources-cheap-source-map
- inline-nosources-cheap-module-source-map
- inline-nosources-source-map
- nosources-cheap-source-map
- nosources-cheap-module-source-map
- nosources-source-map
- hidden-nosources-cheap-source-map
- hidden-nosources-cheap-module-source-map
- hidden-nosources-source-map
- hidden-cheap-source-map
- hidden-cheap-module-source-map
- hidden-source-map
看到這么多,已經(jīng)開(kāi)始慌了。 不過(guò)不用怕, 其實(shí)我們理解核心的幾個(gè)關(guān)鍵字就可以了。

來(lái)看一下文檔上對(duì)這些命名的解釋?zhuān)?/p>
- eval-* :使用eval 生成source map , 不會(huì)生成額外的 .map 文件, 而是在eval 函數(shù)內(nèi)附加 source map 。 推薦用于開(kāi)發(fā)環(huán)境, 因?yàn)? 相對(duì)來(lái)說(shuō)構(gòu)建和熱更新都比較快。
- inline-* : 將SourceMap內(nèi)聯(lián)到原始文件中,同樣 不會(huì)生成額外的 .map 文件。
- hidden-* :addition會(huì)生成source map 但是不會(huì)將其關(guān)聯(lián), 也就是不會(huì)在編譯后的代碼內(nèi)添加上面提到的那個(gè)映射語(yǔ)句。
- nosources-* :sourcemap 中不帶源碼, 但會(huì)有準(zhǔn)確的錯(cuò)誤行列信息, 避免源碼泄露。
- cheap-* : 忽略列信息,source map 只有行映射,可以加快打包速度
- cheap-module-* : moudle 關(guān)鍵子一定是跟 cheap 一起使用的, 表示所映射的階段, 如果沒(méi)有 module 映射的是 loader 處理前的代碼信息,如果加了 module 那就是 loader 處理后的源碼, 舉個(gè)例子,
const a = 1這行, 如果沒(méi)加 module 那拿到的就是轉(zhuǎn)為 es5 的var a = 1, 如果加了module , 那拿到的就是const a = 1
理解了這些之后,再來(lái)看上面這一堆不同類(lèi)型的 source map 也就能看懂了。
什么? 還不懂? 那我們來(lái)動(dòng)手嘗試一下幾個(gè)典型的!
我們?cè)诖a內(nèi)故意打印未定義的變量 c, 看看不同的 source map 下的錯(cuò)誤信息結(jié)果

注意: 行號(hào)為 9
eval
修改配置

首先我們?cè)?devtool 填寫(xiě) eval 。
運(yùn)行構(gòu)建
進(jìn)行一次 run build 構(gòu)建看看。
可以看到生成的結(jié)果, 上方注釋寫(xiě)明了這是來(lái)自哪個(gè)文件的編譯結(jié)果, 當(dāng)然這個(gè)是 webpack 的加載邏輯, 我們這里可以不用太過(guò)關(guān)系, 往內(nèi)部看, 內(nèi)部是一個(gè) eval 函數(shù), 內(nèi)部是編譯后的代碼。

然后我們看到末尾, eval 的末尾有 sourceURL=webpack:///./src/views/About.vue? 。

錯(cuò)誤信息
然后我們運(yùn)行一下項(xiàng)目, 看看他的報(bào)錯(cuò)信息如何。

可以看到其實(shí)并不是非常清晰的, 瞅一眼大概能明白是哪個(gè)文件爆的錯(cuò), 但行號(hào)之類(lèi)的完全不對(duì),而且點(diǎn)擊進(jìn)去的也是編譯后的信息
查看詳情:

完全是編譯后的代碼。
這就是 eval 模式下的 source map 方式, 他不會(huì)生成實(shí)際的 .map 文件, 但會(huì)在 eval 函數(shù)末尾添加對(duì)原本文件的映射語(yǔ)句, 指向源文件本地地址, 同時(shí)調(diào)試體驗(yàn)也較差。 因此也就無(wú)法在生產(chǎn)環(huán)境使用了。
如果想要更清晰的錯(cuò)誤信息還是需要使用 eval-source-map
source-map
最標(biāo)準(zhǔn)的 source-map 打包形式
修改配置:

運(yùn)行構(gòu)建:

可以看到生成了很多 .map 文件

進(jìn)入一份js文件, 我們可以看到代碼的末尾關(guān)聯(lián)了一份 .map 文件
錯(cuò)誤信息:

可以看到錯(cuò)誤定位還是比較準(zhǔn)確的, 找到了正確的 9 行,然后我們點(diǎn)進(jìn)去看看

很完美,是我們正確的源碼信息, 并且成功定位到具體列。
inline-source-map
運(yùn)行構(gòu)建:

沒(méi)有 .map 文件的產(chǎn)出

source map 數(shù)據(jù)直接內(nèi)聯(lián)
錯(cuò)誤信息:

能定位到 行號(hào)
查看詳情:

完美展示,同樣也能夠定位至列
nosources-source-map
運(yùn)行構(gòu)建:

有 .map 文件

有路徑映射
錯(cuò)誤信息:

行號(hào)準(zhǔn)確
查看詳情:

沒(méi)有源碼信息, 無(wú)法加載
hidden-source-map
運(yùn)行構(gòu)建:

有 .map 文件

沒(méi)有映射路徑
錯(cuò)誤信息:

錯(cuò)誤信息模糊
查看詳情:

完全是編譯后的代碼
cheap-source-map
運(yùn)行構(gòu)建:

有 .map 文件

有映射路徑
錯(cuò)誤信息:

行號(hào)不正確
查看詳情:

是被處理過(guò)的代碼,并且沒(méi)有定位到具體列
cheap-module-source-map
運(yùn)行構(gòu)建:

有 .map 文件

有映射路徑
錯(cuò)誤信息:

行號(hào)正確
查看詳情:

正確的源碼,但無(wú)法定位到具體列。
結(jié)尾
搞清楚 source map 這些區(qū)別的關(guān)鍵就在于先要弄懂關(guān)鍵字所表示的含義,其余的都是 “組裝” 。
本文由博客一文多發(fā)平臺(tái) OpenWrite 發(fā)布!