自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

徹底搞懂 Webpack 的 Sourcemap 配置原理

開發(fā) 前端
version 是版本號,file 是文件名,sourceRoot 是源碼根目錄,names 是轉(zhuǎn)換前的變量名,sources 是源碼文件,sourcesContent 是每個(gè) sources 對應(yīng)的源碼的內(nèi)容,mappings 就是一個(gè)個(gè)位置映射了。

用過 webpack 的都知道,webpack 的 sourcemap 配置是比較麻煩的,比如這兩個(gè)配置的區(qū)別:

  • eval-nosources-cheap-module-source-map
  • hidden-module-source-map

是不是分不清楚?

其實(shí)它是有規(guī)律的。

你把配置寫錯(cuò)的時(shí)候,webpack 會提示你一個(gè)正則:

圖片

^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map$

這個(gè)就是配置的規(guī)律,是幾種基礎(chǔ)配置的組合。

搞懂了每一種基礎(chǔ)配置,比如 eval、nosources、cheap、module,按照規(guī)律組合起來,也就搞懂了整體的配置。

那這每一種配置都是什么意思呢?

我們分別來看一下。

在講基礎(chǔ)配置之前,首先講下 sourcemap 是什么:

sourcemap

sourcemap 是關(guān)聯(lián)編譯后的代碼和源碼的,通過一個(gè)個(gè)行列號的映射。

比如編譯后代碼的第 3 行第 4 列,對應(yīng)著源碼里的第 8 行第 5 列這種,這叫做一個(gè) mapping。

sourcemap 的格式如下:

{
version : 3,
file: "out.js",
sourceRoot : "",
sources: ["foo.js", "bar.js"],
names: ["a", "b"],
mappings: "AAgBC,SAAQ,CAAEA;AAAEA",
sourcesContent: ['const a = 1; console.log(a)', 'const b = 2; console.log(b)']
}

version 是版本號,file 是文件名,sourceRoot 是源碼根目錄,names 是轉(zhuǎn)換前的變量名,sources 是源碼文件,sourcesContent 是每個(gè) sources 對應(yīng)的源碼的內(nèi)容,mappings 就是一個(gè)個(gè)位置映射了。

為什么 sources 可以有多個(gè)呢?

因?yàn)榭赡芫幾g產(chǎn)物是多個(gè)源文件合并的,比如打包,一個(gè) bundle.js 就對應(yīng)了 n 個(gè) sources 源文件。

為什么要把變量名單獨(dú)摘出來到 names 里呢?

因?yàn)檫@樣就可以通過下標(biāo)來索引了,mapping 里面就不用保存變量名,只保留 names 的索引就行。

重點(diǎn)是 mappings 部分:

mappings 部分是通過分號;? 和逗號 , 分隔的:

mappings:"AAAAA,BBBBB;CCCCC"

一個(gè)分號就代表一行,這樣就免去了行的映射。

然后每一行可能有多個(gè)位置的映射,用 , 分隔。

那具體的每一個(gè) mapping 都是啥呢?

比如 AAAAA 一共五位,分別有不同的含義:

  • 第一位:轉(zhuǎn)換后代碼的第幾列(行數(shù)通過分號 ; 來確定)
  • 第二位:對應(yīng)轉(zhuǎn)換前的哪個(gè)源碼文件,保存在 sources 里的,這里通過下標(biāo)索引
  • 第三位:對應(yīng)轉(zhuǎn)換前的源碼的第幾行
  • 第四位:對應(yīng)轉(zhuǎn)換前的源碼的第幾列
  • 第五位:對應(yīng)轉(zhuǎn)換前的源碼的哪個(gè)變量名,保存在 names 里的,這里通過下標(biāo)索引

然后經(jīng)過編碼之后,就成了 AAAAA 這種,這種編碼方式叫做 VLQ 編碼。

sourcemap 的格式還是很容易理解的,就是一一映射編譯后代碼的位置和源碼的位置。

各種調(diào)試工具一般都支持 sourcemap 的解析,只要在文件末尾加上這樣一行:

//@ sourceMappingURL=/path/to/source.js.map

運(yùn)行時(shí)就會關(guān)聯(lián)到源碼:

圖片

sourcemap 介紹完了,接下來一起來看下 webpack 的幾種 sourcemap 配置。

前面說過,webpack 的 sourcemap 配置是 eval、cheap、nosources、inline、source-map 等基礎(chǔ)配置的組合。

我們先分別來看下這幾種基礎(chǔ)配置:

eval

eval 的 api 是動(dòng)態(tài)執(zhí)行 JS 代碼的。比如:

圖片

但有個(gè)問題,eval 的代碼打不了斷點(diǎn)。

怎么解決這個(gè)問題呢?

瀏覽器支持了這樣一種特性,只要在 eval 代碼的最后加上 //# sourceURL=xxx,那就會以 xxx 為名字把這段代碼加到 sources 里。那不就可以打斷點(diǎn)了么?

比如這樣:

圖片

執(zhí)行以后,你會發(fā)現(xiàn) sources 多了光.js的文件:

圖片

它是可以打斷點(diǎn)的,比如在 add 里打個(gè)斷點(diǎn),然后再執(zhí)行 eval。

你會發(fā)現(xiàn)它斷住了!

圖片

除了指定 source 文件外,還可以進(jìn)一步指定 sourcemap 來映射到源碼:

圖片

這樣,動(dòng)態(tài) eval 的代碼也能關(guān)聯(lián)到源碼,并且能打斷點(diǎn)了!

webpack 就利用了 eval 這個(gè)特性來優(yōu)化的 sourcemap 生成的性能,比如你可以指定 devtool 為 eval:

圖片

生成的代碼就是每個(gè)模塊都被 eval 包裹的,并且有 sourceUrl 來指定文件名:

圖片

這樣有啥好處呢?

快呀,因?yàn)橹灰付▊€(gè)文件名就行,不用生成 sourcemap。sourcemap 的生成還是很慢的,要一個(gè)個(gè) mapping 的處理,做編碼之類的。

每個(gè)模塊的代碼都被 eval 包裹,那么執(zhí)行的時(shí)候就會在 sources 里生成對應(yīng)的文件,這樣就可以打斷點(diǎn)了:

圖片

不過這樣只是把每個(gè)模塊的代碼分了出去,并沒有做源碼的關(guān)聯(lián),如果相關(guān)聯(lián)源碼,可以再開啟 sourcemap:

圖片

你會發(fā)現(xiàn)生成的代碼也是用 eval 包裹的,但除了 sourceUrl 外,還有 sourceMappingUrl:

圖片

再運(yùn)行的時(shí)候除了 eval 的代碼會生成文件放在 sources 外,還會做 sourcemap 的映射:

圖片

webpack 的 sourcemap 的配置就利用了瀏覽器對 eval 代碼的調(diào)試支持。

所以為什么這個(gè)配置項(xiàng)不叫 sourcemap 而叫 devtool 呢?

因?yàn)椴恢皇?sourcemap 呀,eval 的方式也行。

再來看下一個(gè)基礎(chǔ)配置:

source-map

source-map 的配置是生成獨(dú)立的 sourcemap 文件:

圖片

圖片

圖片

可以關(guān)聯(lián),也可以不關(guān)聯(lián),比如加上 hidden,就是生成 sourcemap 但是不關(guān)聯(lián):

圖片

圖片

生產(chǎn)環(huán)境就不需要關(guān)聯(lián) sourcemap,但是可能要生成 sourcemap 文件,把它上傳到錯(cuò)誤管理平臺之類的,用來映射線上代碼報(bào)錯(cuò)位置到對應(yīng)的源碼。

此外,還可以配置成 inline 的:

圖片

這個(gè)就是通過 dataUrl 的方式內(nèi)聯(lián)在打包后的文件里:

圖片

這幾個(gè)配置還是很好懂的,我們來看下一個(gè)基礎(chǔ)配置:

cheap

sourcemap 慢主要是處理映射比較慢,很多情況下我們不需要映射到源碼的行和列,只要精確到行就行,這時(shí)候就可以用 cheap。

不精確到列能提升 souremap 生成速度,但是會犧牲一些精準(zhǔn)度:

圖片

我們再來看下一個(gè)基礎(chǔ)配置:

module

webpack 中對一個(gè)模塊會進(jìn)行多次處理,比如經(jīng)過 loader A 做一次轉(zhuǎn)換,再用 laoder B 做一次轉(zhuǎn)換,之后打包到一起。

每次轉(zhuǎn)換都會生成 sourcemap,那也就是有多個(gè) sourcemap:

圖片

默認(rèn) sourcemap 只是能從 bundle 關(guān)聯(lián)到模塊的代碼,也就是只關(guān)聯(lián)了最后那個(gè) sourcemap。

那如果你想調(diào)試最初的源碼怎么辦呢?

那就把每一次的 loader 的 sourcemap 也關(guān)聯(lián)起來,這就是 module 配置的作用。

比如我們想調(diào)試 React 最初的源碼,那就要先生成有 sourcemap 的代碼:

圖片

怎么生成有 sourcemap 的 React 代碼可以看我前面一篇文章。

有了 sourcemap 之后,要配置下 sourcemap-loader:

圖片

它的作用就是讀取源碼的 sourcemap,傳遞給后面的 loader。

之后配置 devtool,加上 module:

圖片

再次運(yùn)行,你就會發(fā)現(xiàn) react 代碼能映射到最初的源碼了:

圖片

之前只能從 bundle.js 映射到編譯后的模塊代碼,也就是這一步:

圖片

devtool 配置加上 module,就支持了 loader 的 sourcemap 映射,然后再加上 sourmap-loader 來讀取源碼的 sourcemap,這樣就能一次性映射回最初的源碼:

圖片

當(dāng)你想調(diào)試最初的源碼的時(shí)候,module 的配置就很有用了。

接下來還有最后一個(gè)基礎(chǔ)配置:

nosources

sourcemap 里是有 sourceContent 部分的,也就是直接把源碼貼在這里,這樣的好處是根據(jù)文件路徑查不到文件也可以映射,但這樣會增加 sourcemap 的體積。

如果你確定根據(jù)文件路徑能查找到源文件,那不生成 sourceContent 也行。

比如 devtool 配置為 source-map,生成的 sourcemap 是這樣的:

圖片

當(dāng)你加上 nosources 之后,生成的 sourcemap 就沒有 sourceContent 部分了:

圖片

sourcemap 文件大小會小很多。

基礎(chǔ)配置講完了,接下來就是各種組合了,這個(gè)就比較簡單了,就算組合錯(cuò)了,webpack 也會提示你應(yīng)該按照什么順序來組合。

它是按照這個(gè)正則來校驗(yàn)的:^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map$

我們討論下最佳實(shí)踐:

線上的時(shí)候當(dāng)然要啟用 hidden,不關(guān)聯(lián) sourcemap,但要生成 sourcemap,不大需要 module 來映射回最初的源碼,所以可能是 hidden-source-map 這種。

開發(fā)的時(shí)候可以用 eval 的方式,這樣是每個(gè)模塊單獨(dú)做映射,不用從 bundle.js 開始映射,然后 cheap 也可以開啟,只映射到源碼的某一行,提升生成速度,一般需要 module 來映射回最初的源碼,所以可能是 eval-cheap-module-source-map 這種。

當(dāng)然,具體怎么配置是按照需求來的,我們理解了每個(gè)基礎(chǔ)配置,知道怎么組合就可以了。

不知道有沒有同學(xué)會覺得這樣寫比較麻煩,能不能每個(gè)基礎(chǔ)配置用 true、false 的方式配置呢?

確實(shí)可以,有這樣一個(gè)插件:SourceMapDevToolPlugin

它有很多 option,比如 module、columns、noSources 等:

圖片

相當(dāng)于是 devtool 的另一種配置方式,啟用它需要把 devtool 設(shè)置為 false。

而且它可以控制更多東西,比如修改 sourcemap 的 url 和文件名等:

圖片

當(dāng)你需要做更多的 sourcemap 生成方式的控制的時(shí)候,可以使用這個(gè) webpack 插件。

總結(jié)

webpack 的 sourcemap 配置比較麻煩,但其實(shí)也是有規(guī)律的。

它是對一些基礎(chǔ)配置按照一定順序的組合,理解了每個(gè)基礎(chǔ)配置,知道了怎么組合就理解了各種 devtool 配置。

  • eval:瀏覽器 devtool 支持通過 sourceUrl 來把 eval 的內(nèi)容單獨(dú)生成文件,還可以進(jìn)一步通過 sourceMappingUrl 來映射回源碼,webpack 利用這個(gè)特性來簡化了 sourcemap 的處理,可以直接從模塊開始映射,不用從 bundle 級別。
  • cheap:只映射到源代碼的某一行,不精確到列,可以提升 sourcemap 生成速度
  • source-map:生成 sourcemap 文件,可以配置 inline,會以 dataURL 的方式內(nèi)聯(lián),可以配置 hidden,只生成 sourcemap,不和生成的文件關(guān)聯(lián)
  • nosources:不生成 sourceContent 內(nèi)容,可以減小 sourcemap 文件的大小
  • module:sourcemap 生成時(shí)會關(guān)聯(lián)每一步 loader 生成的 sourcemap,配合 sourcemap-loader 可以映射回最初的源碼

理解了這些基礎(chǔ)配置項(xiàng),根據(jù) ^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map$ 的規(guī)律來進(jìn)行組合,就可以實(shí)現(xiàn)各種需求下的 sourcemap 配置。

當(dāng)然,這種 sourcemap 配置還不夠細(xì)致,比如 sourcemap 的 url 怎么生成,文件名是什么。如果想對這些做配置,可以關(guān)掉 devtool,啟用 SourceMapDevToolPlugin 來配置。

雖然 webapck 的 sourcemap 配置方式比較多,但最底層也就是瀏覽器支持的文件級別的 sourcemap 還有 eval 代碼的 source 映射和 sourcemap 這兩種機(jī)制。其余的方式都是基于這兩種機(jī)制的封裝。

理解了瀏覽器 devtool的機(jī)制,webpack 封裝出的基礎(chǔ)配置,知道了組合規(guī)則,就可以應(yīng)對各種需求的 sourcemap 配置。

責(zé)任編輯:武曉燕 來源: 神光的編程秘籍
相關(guān)推薦

2023-05-29 08:12:38

2023-10-18 10:55:55

HashMap

2021-10-11 11:58:41

Channel原理recvq

2021-10-09 19:05:06

channelGo原理

2021-07-16 11:35:20

Java線程池代碼

2022-04-24 11:06:54

SpringBootjar代碼

2021-07-08 10:08:03

DvaJS前端Dva

2021-12-15 09:21:59

Webpack 前端Sourcemap

2025-04-21 04:00:00

2020-04-28 22:12:30

Nginx正向代理反向代理

2021-12-29 17:29:07

KubernetesEvents集群

2023-09-28 08:15:05

SpringBean加載

2021-10-15 08:32:03

RocketMQ數(shù)據(jù)結(jié)構(gòu)架構(gòu)

2024-10-15 17:12:38

代碼父子線程開源

2023-05-31 08:19:23

Webpack4Webpack 5

2021-08-18 23:10:56

setState代碼性能

2024-01-03 13:39:00

JS,Javascrip算法

2025-01-13 16:00:00

服務(wù)網(wǎng)關(guān)分布式系統(tǒng)架構(gòu)

2025-04-11 05:55:00

2021-02-01 11:30:13

React前端調(diào)度
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號