成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Webpack 實戰(zhàn)系列一:正確使用 Sourcemap

開發(fā) 前端
Sourcemap 協(xié)議最初由 Google 設(shè)計并率先在 Closure Inspector 實現(xiàn),它能夠?qū)⒔?jīng)過壓縮、混淆、合并的代碼還原回未打包狀態(tài),幫助開發(fā)者在生產(chǎn)環(huán)境中精確定位問題發(fā)生的行列位置。

[[440484]]

一、什么是 Sourcemap

Sourcemap 協(xié)議最初由 Google 設(shè)計并率先在 Closure Inspector 實現(xiàn),它能夠?qū)⒔?jīng)過壓縮、混淆、合并的代碼還原回未打包狀態(tài),幫助開發(fā)者在生產(chǎn)環(huán)境中精確定位問題發(fā)生的行列位置。

發(fā)展至今,Sourcemap 已廣泛受 Webpack、Rollup、Babel、Less、Typescript、Chrome、Safari、VS Code 等工具支持。

參考:https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k

實現(xiàn)上,Sourcemap 由三部分組成:

  • 開發(fā)者編寫的原始代碼
  • 經(jīng)過 Webpack、Rollup 等工程化工具壓縮、轉(zhuǎn)化、合并后的產(chǎn)物,且產(chǎn)物中必須包含指向 Sourcemap 文件地址的 //# sourceMappingURL=https://xxxx/bundle.js.map 指令
  • 記錄原始代碼與經(jīng)過工程化處理代碼之間位置映射關(guān)系 Map 文件

頁面初始運行時只會加載編譯構(gòu)建產(chǎn)物,直到特定事件發(fā)生 —— 例如在 Chrome 打開 Devtool 面板時,才會根據(jù) //# sourceMappingURL 內(nèi)容自動加載 Map 文件,并按 Sourcemap 協(xié)議約定的映射規(guī)則將代碼重構(gòu)還原回原始形態(tài),這既能保證終端用戶的性能體驗,又能幫助開發(fā)者快速還原現(xiàn)場,提升線上問題的定位與調(diào)試效率。

1.1 示例

以 Webpack 為例,設(shè)置 devtool = 'source-map' 即可同時打包出代碼產(chǎn)物 xxx.js 文件與同名 xxx.js.map 文件,Map 文件通常為 JSON 格式,內(nèi)容如:

  1.     "version": 3, 
  2.     "sources": [ 
  3.         "webpack:///./src/index.js" 
  4.     ], 
  5.     "names": ["name""console""log"], 
  6.     "mappings"";;;;;AAAA,IAAMA,IAAI,GAAG,QAAb;AAEAC,OAAO,CAACC,GAAR,CAAYF,IAAZ,E"
  7.     "file""main.js"
  8.     "sourcesContent": [ 
  9.         "const name = 'tecvan';\n\nconsole.log(name)" 
  10.     ], 
  11.     "sourceRoot""" 

各字段含義分別為:

  • version:指代 sourcemap 版本,目前最新版本為 3names:字符串數(shù)組,記錄原始代碼中出現(xiàn)的變量名
  • file:字符串,該 Sourcemap 文件對應(yīng)的編譯產(chǎn)物文件名
  • sourcesContent:字符串數(shù)組,原始代碼的內(nèi)容
  • sourceRoot:字符串,源文件根目錄
  • sources:字符串數(shù)組,原始文件路徑名,與 sourcesContent 內(nèi)容一一對應(yīng)
  • mappings:字符串數(shù)組,記錄打包產(chǎn)物與原始代碼的位置映射關(guān)系

使用時,瀏覽器會按照 mappings 記錄的數(shù)值關(guān)系,將產(chǎn)物代碼映射回 sourcesContent 數(shù)組所記錄的原始代碼文件、行、列位置,這里面最復(fù)雜難懂的點就在于 mappings 字段的規(guī)則。

1.2 源碼映射與 VLQ

Sourcemap 最初版本生成的 .map 文件非常大,體積大概為編譯產(chǎn)物的 10 倍;V2 引入 base64 編碼等算法將之減少 20% ~ 30%;而最新版本 V3 又在 V2 基礎(chǔ)上引入 VLQ 等算法,體積進一步壓縮了 50%。這一系列進化造就了一個效率極高的 Sourcemap 體系,但伴隨而來的則是較為復(fù)雜的 mappings 編碼規(guī)則。

1.2.1 mappings 編碼規(guī)則

舉個例子,對于下面的代碼:

當 devtool = 'source-map' 時,Webpack 生成的 mappings 字段為:

  1. ;;;;;AAAA,IAAMA,IAAI,GAAG,QAAb;AAEAC,OAAO,CAACC,GAAR,CAAYF,IAAZ,E 

字段內(nèi)容包含三層結(jié)構(gòu):

  • 以 ; 分割的「行映射」,每一個 ; 對應(yīng)編譯產(chǎn)物每一行到源碼的映射,上例經(jīng)過分割后:
  1.   // 產(chǎn)物第 1-5 行內(nèi)容為 Webpack 生成的 runtime,不需要記錄映射關(guān)系 
  2.   '''''''''',  
  3.   // 產(chǎn)物第 6 行的映射信息 
  4.   'AAAA,IAAMA,IAAI,GAAG,QAAb',  
  5.   // 產(chǎn)物第 7 行的映射信息 
  6.   'AAEAC,OAAO,CAACC,GAAR,CAAYF,IAAZ,E' 
  • 以 , 分割的「片段映射」,每一個 , 對應(yīng)該行中每一個代碼片段到源碼的映射,上例經(jīng)過分割后:
  1.   // 產(chǎn)物第 1-5 行內(nèi)容為 Webpack 生成的 runtime,不需要記錄映射關(guān)系 
  2.   '''''''''',  
  3.   // 產(chǎn)物第 6 行的映射信息 
  4.   [ 
  5.     // 片段 `var` 到 `const` 的映射 
  6.     'AAAA',  
  7.     // 片段 `name` 到 `name` 的映射 
  8.     'IAAMA',  
  9.     // 等等 
  10.     'IAAI''GAAG''QAAb'],  
  11.   // 產(chǎn)物第 7 行的映射信息 
  12.   ['AAEAC''OAAO''CAACC''GAAR''CAAYF''IAAZ''E'

第三層邏輯為片段映射到源碼的具體位置,以上例 IAAMA 為例:

  • 第一位 I 該代碼片段在產(chǎn)物中列數(shù)
  • 第二位 A 代表源碼文件的索引,即該片段對標到 sources 數(shù)組的元素下標
  • 第三位 A 代表片段在源碼文件的行數(shù)
  • 第四位 M 代表片段在源碼文件的列數(shù)
  • 第五位 A 代表該片段對應(yīng)的名稱索引,即該片段對標到 names 數(shù)組的元素下標

上述第1、2層邏輯比較簡單,唯一需要注意的是片段之間是一種相對偏移關(guān)系,例如對于上例第六行映射值:AAAA,IAAMA,IAAI,GAAG,QAAb,每一個片段的第一位 —— 即片段列數(shù)為 A,I,I,G,Q,分別代表:

  • A :第 A 列
  • I :第 A + I 列
  • I :第 A + I + I 列
  • G :第 A + I + I + G 列
  • Q :第 A + I + I + G + Q 列

這種相對偏移能減少 Sourcemap 產(chǎn)物的體積,提升整體性能。

而第三層的片段位置映射則用到了一種比較高效數(shù)值編碼算法 —— VLQ(Variable-length Quantity)。

1.2.2 VLQ編碼

參考:https://en.wikipedia.org/wiki/Variable-lengsth_quantity

VLQ 本質(zhì)上是一種將整數(shù)數(shù)值轉(zhuǎn)換為 Base64 的編碼算法,它先將任意大的整數(shù)轉(zhuǎn)換為一系列六位字節(jié)碼,再按 Base64 規(guī)則轉(zhuǎn)換為一串可見字符。VLQ 使用六位比特存儲一個編碼分組,例如:

數(shù)字 7 經(jīng)過 VLQ 編碼后,結(jié)果為 001110,其中:

  • 第一位為連續(xù)標志位,標識后續(xù)分組是否為同一數(shù)字;
  • 第六位表示該數(shù)字的正負符號,0為正整數(shù),1為負整數(shù);
  • 中間第 2-5 為實際數(shù)值。

這樣一個六位編碼分組,就可以按照 Base64 的映射規(guī)則轉(zhuǎn)換為 ABC 等可見字符,例如上述數(shù)字 7 編碼結(jié)果 001110,等于十進制的 14,按 Base64 字碼表可映射為字母 O。

但是,分組中只有中間的 4 個字節(jié)用于表示數(shù)值,因此單個分組只能表達 「-15 ~ 15」 之間的數(shù)值范圍,對于超過這個范圍的整數(shù)需要組合多個分組共同表達同一數(shù)字,組合規(guī)則:

  • 第一個分組的最后一位為符號位,其它分組從 2-6 均為數(shù)值位
  • 取二進制值最后四位為第一個分組值,之后從后到前,每 5 位為一個劃分為一個分組
  • 除最后一個分組外,其余分組的連續(xù)標志位都設(shè)置為 1

例如對于十進制 -17,其二進制為 10001 (取 17 的二進制) 共5位,首先從后到前拆分為兩組,后四位 0001 為第一組,連續(xù)標志位為 1,符號位為 1,結(jié)果為 1,0001,1;剩下的 1 分配到第二個 —— 也是最后一個分組,連續(xù)標志位為 0,結(jié)果為 0,00001。按 Base64 規(guī)則 [100011, 000001] 最終映射為 jA。

  1. 十進制     二進制               VLQ    Base64 
  2.   -17 => 1,0001 => 100011, 000001 =>     jA 

同樣的,對于更大的數(shù)字,例如 1200,其二進制為 10010110000,分組為 [10, 01011, 0000],從后到前編碼,第一個分組為 1,0000,0;第二個分組為 1,01011;最后一個分組為 0,00010。按 Base64 映射為 grC。

  1. 十進制            二進制                     VLQ    Base64 
  2.  1200 => 10;01011;0000 => 100000,101011,000010 =>    grC 

1.2.3 解碼 mappings

結(jié)合 VLQ 編碼知識,我們再回過來頭來解讀本章開頭的例子,對于代碼:

編譯生成 mappings:

  1. ;;;;;AAAA,IAAMA,IAAI,GAAG,QAAb;AAEAC,OAAO,CAACC,GAAR,CAAYF,IAAZ,E 

按行、片段規(guī)則分割后,得出如下片段:

  1.   // 產(chǎn)物第 1-5 行內(nèi)容為 Webpack 生成的 runtime,不需要記錄映射關(guān)系 
  2.   '''''''''',  
  3.   // 產(chǎn)物第 6 行的映射信息 
  4.   ['AAAA''IAAMA''IAAI''GAAG''QAAb'],  
  5.   // 產(chǎn)物第 7 行的映射信息 
  6.   ['AAEAC''OAAO''CAACC''GAAR''CAAYF''IAAZ''E'

以第 6 行 ['AAAA', 'IAAMA', 'IAAI', 'GAAG', 'QAAb'] 為例:

  • AAAA 解碼結(jié)果為 [000000, 000000, 000000, 000000],即產(chǎn)物第 6 行「第0列」映射到 sources[0] 文件的「第0行」,「第0列」,實際對應(yīng) var 到 const 的位置映射
  • IAAMA 解碼結(jié)果為 [001000, 000000, 000000, 001100, 000000],即產(chǎn)物第 6 行第4列映射到 sources[0] 文件的「第0行」,「第6列」,實際對應(yīng)產(chǎn)物 name 到源碼 name 的位置映射

其它片段以此類推。

二、使用 Sourcemap

Webpack 提供了兩種設(shè)置 Sourcemap 的方式,一是通過 devtool 配置項設(shè)置 Sourcemap 規(guī)則短語;二是直接使用 SourceMapDevToolPlugin 或 EvalSourceMapDevToolPlugin 插件深度定制 Sourcemap 的生成邏輯。

下面我們先展開介紹比較晦澀的 devtool 配置項,理解 Webpack 所提供的各種 Sourcemap 功能規(guī)則。

2.1 使用devtooldevtool

支持 25 種字符串枚舉值,包括 eval、source-map、eval-source-map 等,分開來看都特別晦澀,但仔細觀察可發(fā)現(xiàn)這些值都是由 inline、eval、source-map、nosources、hidden、cheap、module 七種關(guān)鍵詞組合而成,這些關(guān)鍵詞各自代表一項 Sourcemap 規(guī)則。

2.1.1 eval

當 devtool 值包含 eval 時,生成的模塊代碼會被包裹進一段 eval 函數(shù)中,且模塊的 Sourcemap 信息通過 //# sourceURL 直接掛載在模塊代碼內(nèi)。例如:

  1. eval("var foo = 'bar'\n\n\n//# sourceURL=webpack:///./src/index.ts?"

eval 模式編譯速度通常比較快,但產(chǎn)物中直接包含了 Sourcemap 信息,因此只推薦在開發(fā)環(huán)境中使用。

2.1.2 source-map

當 devtool 包含 source-map 時,Webpack 才會生成 Sourcemap 內(nèi)容。例如,對于 devtool = 'source-map',產(chǎn)物會額外生成 .map 文件,形如:

  1.     "version": 3, 
  2.     "sources": [ 
  3.         "webpack:///./src/index.ts" 
  4.     ], 
  5.     "names": [ 
  6.         "console"
  7.         "log" 
  8.     ], 
  9.     "mappings""AACAA,QAAQC,IADI"
  10.     "file""bundle.js"
  11.     "sourcesContent": [ 
  12.         "const foo = 'bar';\nconsole.log(foo);" 
  13.     ], 
  14.     "sourceRoot""" 

實際上,除 eval 之外的其它枚舉值都包含該字段。

2.1.3 cheap

當 devtool 包含 cheap 時,生成的 Sourcemap 內(nèi)容會拋棄「列」維度的信息,這就意味著瀏覽器只能映射到代碼行維度。例如 devtool = 'cheap-source-map' 時,產(chǎn)物:

  1.     "version": 3, 
  2.     "file""bundle.js"
  3.     "sources": [ 
  4.         "webpack:///bundle.js" 
  5.     ], 
  6.     "sourcesContent": [ 
  7.         "console.log(\"bar\");" 
  8.     ], 
  9.     // 帶 cheap 效果: 
  10.     "mappings""AAAA"
  11.     // 不帶 cheap 效果: 
  12.     // "mappings""AACAA,QAAQC,IADI"
  13.     "sourceRoot""" 

瀏覽器映射效果:

雖然 Sourcemap 提供的映射功能可精確定位到文件、行、列粒度,但有時在「行」級別已經(jīng)足夠幫助我們達到調(diào)試定位的目的,此時可選擇使用 cheap 關(guān)鍵字,簡化 Sourcemap 內(nèi)容,減少 Sourcemap 文件體積。

2.1.4 modulemodule

關(guān)鍵字只在 cheap 場景下生效,例如 cheap-module-source-map、eval-cheap-module-source-map。當 devtool 包含 cheap 時,Webpack 根據(jù) module 關(guān)鍵字判斷按 loader 聯(lián)調(diào)處理結(jié)果作為 source,還是按處理之前的代碼作為 source。例如:

注意觀察上例 sourcesContent 字段,左邊 devtool 帶 module 關(guān)鍵字,因此此處映射的是包含 class Person 的最原始代碼;而右邊生成的 sourcesContent 則是經(jīng)過 babel-loader 編譯處理的內(nèi)容。

2.1.5 nosources

當 devtool 包含 nosources 時,生成的 Sourcemap 內(nèi)容中不包含源碼內(nèi)容 —— 即 sourcesContent 字段。例如 devtool = 'nosources-source-map' 時,產(chǎn)物:

  1.     "version": 3, 
  2.     "sources": [ 
  3.         "webpack:///./src/index.ts" 
  4.     ], 
  5.     "names": [ 
  6.         "console"
  7.         "log" 
  8.     ], 
  9.     "mappings""AACAA,QAAQC,IADI"
  10.     "file""bundle.js"
  11.     "sourceRoot""" 

雖然沒有帶上源碼,但 .map 產(chǎn)物中還帶有文件名、 mappings 字段、變量名等信息,依然能夠幫助開發(fā)者定位到代碼對應(yīng)的原始位置,配合 sentry 等工具提供的源碼映射功能,可在異地還原諸如錯誤堆棧之類的信息。

2.1.6 inline

當 devtool 包含 inline 時,Webpack 會將 Sourcemap 內(nèi)容編碼為 Base64 DataURL,直接追加到產(chǎn)物文件中。例如對于 devtool = 'inline-source-map',產(chǎn)物:

  1. console.log("bar"); 
  2. //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOlsiY29uc29sZSIsImxvZyJdLCJtYXBwaW5ncyI6IkFBQ0FBLFFBQVFDLElBREkiLCJmaWxlIjoiYnVuZGxlLmpzIiwic291cmNlc0NvbnRlbnQiOlsiY29uc3QgZm9vID0gJ2Jhcic7XG5jb25zb2xlLmxvZyhmb28pOyJdLCJzb3VyY2VSb290IjoiIn0= 

inline 模式編譯速度較慢,且產(chǎn)物體積非常大,只適合開發(fā)環(huán)境使用。

2.1.7 hidden

通常情況下,產(chǎn)物中必須攜帶 //# sourceMappingURL= 指令,瀏覽器才能正確找到 Sourcemap 文件,

當 devtool 包含 hidden 時,編譯產(chǎn)物中不包含 //# sourceMappingURL= 指令。例如:

兩者區(qū)別僅在于編譯產(chǎn)物最后一行的 //# sourceMappingURL= 指令,當你需要 Sourcemap 功能,又不希望瀏覽器 Devtool 工具自動加載時,可使用此選項。你也可以通過以下操作手動打開 Sourcemap:

2.1.8 小結(jié)

總結(jié)一下,Webpack 的 devtool 值都是由以上七種關(guān)鍵字的一個或多個組成,雖然提供了 27 種候選項,但邏輯上都是由上述規(guī)則疊加而成,例如:

  • cheap-source-map:代表 「不帶列映射」 的 Sourcemap
  • eval-nosources-cheap-source-map:代表 「以」 **eval** 「包裹模塊代碼」 ,且 **.map** 「映射文件中不帶源碼」 ,且 「不帶列映射」 的 Sourcemap

其它選項以此類推。最后再總結(jié)一下:

對于開發(fā)環(huán)境,適合使用:

  • eval:速度極快,但只能看到原始文件結(jié)構(gòu),看不到打包前的代碼內(nèi)容
  • cheap-eval-source-map:速度比較快,可以看到打包前的代碼內(nèi)容,但看不到 loader 處理之前的源碼
  • cheap-module-eval-source-map:速度比較快,可以看到 loader 處理之前的源碼,不過定位不到列級別
  • eval-source-map:初次編譯較慢,但定位精度最高

對于生產(chǎn)環(huán)境,則適合使用:

  • source-map:信息最完整,但安全性最低,外部用戶可輕易獲取到壓縮、混淆之前的源碼,慎重使用
  • hidden-source-map:信息較完整,安全性較低,外部用戶獲取到 .map 文件地址時依然可以拿到源碼
  • nosources-source-map:源碼信息確實,但安全性較高,需要配合 Sentry 等工具實現(xiàn)完整的 Sourcemap 映射

2.2 使用插件

上面介紹的 devtool 配置項本質(zhì)上只是一種方便記憶、使用的規(guī)則縮寫短語,Sourcemap 的底層處理邏輯實際由 SourceMapDevToolPlugin 與 EvalSourceMapDevToolPlugin 插件實現(xiàn)。

參考:https://webpack.js.org/plugins/source-map-dev-tool-plugin/

在 devtool 基礎(chǔ)上,插件還提供了更多更細粒度的配置項,用于滿足更復(fù)雜的需求場景,包括:

  • 使用 test、include、exclude 配置項設(shè)定對那些 bundle 生成 Sourcemap
  • 使用 append、filename、moduleFilenameTemplate、publicPath 配置項設(shè)定 Sourcemap 文件的文件名、URL

使用方法與其它插件無異,如:

  1. const webpack = require('webpack'); 
  2. module.exports = { 
  3.   // ... 
  4.   devtool: false
  5.   plugins: [new webpack.SourceMapDevToolPlugin({ 
  6.       exclude: ['vendor.js'
  7.   })], 
  8. }; 

插件配置規(guī)則較簡單,此處不贅述。

三、總結(jié)

至此,有關(guān) Sourcemap 的大部分內(nèi)容就講解完畢了,讀者們需要了解 Sourcemap 是一種高效位置映射算法,它將產(chǎn)物到源碼之間的位置關(guān)系表達為 mappings 分層設(shè)計與 VLQ 編碼規(guī)則,再通過 Chrome、Safari、VS Code、Sentry 等工具異地還原為接近開發(fā)狀態(tài)的源碼形式。

在 Webpack 場景下,通常只需要選擇適當?shù)?devtool 短語即可滿足大多數(shù)場景需求,特殊情況下也可以直接使用 SourceMapDevToolPlugin 做更深度的定制化。

 

責(zé)任編輯:姜華 來源: Tecvan
相關(guān)推薦

2022-08-26 13:24:03

version源碼sources

2021-11-15 09:44:49

Webpack 前端 Scope Hois

2019-03-05 10:20:49

WebWebpack分離數(shù)據(jù)

2023-05-31 08:19:23

Webpack4Webpack 5

2021-05-31 05:36:43

WebpackJavaScript 前端

2023-03-27 10:46:53

SourceMap字符串代碼

2021-11-09 09:57:46

Webpack 前端分包優(yōu)化

2021-10-25 10:23:49

Webpack 前端Tree shakin

2021-03-16 14:45:39

Zabbix 5.2Grafana監(jiān)控

2021-06-28 05:59:17

Webpack 前端打包與工程化

2021-12-21 14:00:25

WebpackDevServer的開發(fā)

2021-09-13 09:40:35

Webpack 前端HMR 原理

2021-08-26 10:30:29

WebpackTree-Shakin前端

2011-09-07 09:21:04

2017-05-26 11:00:38

Python算法

2021-12-16 22:02:28

webpack原理模塊化

2011-08-19 10:17:53

2020-08-31 06:54:37

注解脫敏ELK

2021-07-12 11:35:13

Go協(xié)程Goroutine

2009-02-20 11:03:25

Vista特點
點贊
收藏

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

主站蜘蛛池模板: 成人羞羞国产免费视频 | 亚洲综合99| av黄色免费| 不卡在线一区 | 成人三级在线观看 | 亚洲一区视频在线播放 | 欧洲色| 亚洲视频免费 | 久久国产高清 | 亚洲一区二区av在线 | 国产一区二区精品自拍 | 一级毛片在线播放 | 国产精品不卡视频 | 欧美xxxx黑人又粗又长 | 在线日韩欧美 | 亚洲电影第三页 | 欧美片网站免费 | 日韩国产免费 | 99视频在线免费观看 | 欧美激情一区二区 | 日韩伦理一区二区 | 欧美vide | 久草网在线视频 | 日韩欧美中文 | 九九亚洲 | 91精品国产综合久久香蕉922 | 久久国产区 | 99久久久国产精品免费消防器 | 2018国产大陆天天弄 | 91精品国产一区二区三区动漫 | 夏同学福利网 | 嫩草视频网 | 亚洲欧美视频一区二区 | 国产精品视频一区二区三区四蜜臂 | 国产精品影视 | 一区二区三区四区五区在线视频 | 午夜激情免费 | 午夜精品一区二区三区免费视频 | 少妇一区在线观看 | 91视频精选 | 日韩视频免费看 |