<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SourceMap知多少:介紹與實踐

          共 4397字,需瀏覽 9分鐘

           ·

          2020-09-10 07:49

          (給全棧前端精選加星標,提升前端技能

          作者:騰訊IMWeb前端團隊


          01


          首先說說sourceMap


          說起sourceMap大家肯定都不陌生,隨著前端工程化的演進,我們打包出來的代碼都是混淆壓縮過的,當源代碼經(jīng)過轉(zhuǎn)換后,調(diào)試就成了一個問題。在瀏覽器中調(diào)試時,如何判斷原始代碼的位置?


          為了解決這個問題,google 提出了sourceMap 的想法,并在chorme上最先支持sourceMap的使用。sourceMap 由于包含許多信息,前期也經(jīng)過多版的編碼算法優(yōu)化,最后在2011年探索出了Source Map Revision 3.0 ,這個版本也就是我們現(xiàn)在一直在使用的sourceMap版本。這一版本的mapping信息使用Base64 VLQ 編碼,大大縮小了.map文件的體積。

          sourceMap可以幫我們直接定位到編譯前代碼的特定位置,接下來我們直接拿個sourceMap文件來看看它包含了一些什么信息:



          上面可以看到,sourceMap其實就是就是一段維護了前后代碼映射關系的json描述文件,包含了以下一些信息:

          • version:sourcemap版本(現(xiàn)在都是v3)

          • file:轉(zhuǎn)換后的文件名。

          • sourceRoot:轉(zhuǎn)換前的文件所在的目錄。如果與轉(zhuǎn)換前的文件在同一目錄,該項為空。

          • sources:轉(zhuǎn)換前的文件。該項是一個數(shù)組,表示可能存在多個文件合并。

          • names:轉(zhuǎn)換前的所有變量名和屬性名。

          • mappings:記錄位置信息的字符串。
            mappings 信息是關鍵,它使用Base64 VLQ 編碼,包含了源代碼與生成代碼的位置映射信息。mappings的編碼原理詳解可見:http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html,這里就不再詳述。

          02


          webpack中的sourceMap配置


          ?webpack 給出了多種sourceMap配置方式,相信很多人第一眼看到的時候和我一樣,疑惑這些都有啥區(qū)別




          ???????


          其實不難發(fā)現(xiàn)這么多配置,這些就是source-map和eval、inline、cheap、module 的自由組合。所以我們來拆開看下每項配置。

          為了方便演示,這里的源代碼只包含了一行代碼

          1. console.log('hello world');

          先給大家展示,最原始的只設置’source-map’配置,可以看到輸出了兩個文件,其中包含一個map文件


          main.js文件內(nèi)容如下,map文件上面展示過了,就不再展示內(nèi)容了


          1


          eval

          每個模塊用eval()包裹執(zhí)行。

          1)devtool: eval
          我們先看看單獨的eval配置,這個配置相對于其他會特殊一點 。因為配置里沒有sourceMap,實際上它也會生出map,只是它映射的是轉(zhuǎn)換后的代碼,而不是映射到原始代碼。

          2)devtool: eval-source-map
          所以eval-source-map就會帶上源碼的sourceMap,打包結(jié)果如下:




          值得注意的是加了eval的配置生成的sourceMap會作為DataURI嵌入,不單獨生成.map文件


          對于eval的構建模式,我們可以看看官方的描述

          devtool: “eval-source-map” is really as good as devtool: “source-map”, but can cache SourceMaps for modules. It’s much faster for rebuilds.

          可以看出官方是比較推薦開發(fā)場景下使用的,因為它能cache sourceMap,從而rebuild的速度會比較快。


          2


          inline

          inline配置想必大家肯定已經(jīng)能猜到了,就是將map作為DataURI嵌入,不單獨生成.map文件。
          devtool: inline-source-map構建出來的文件如下, 這個比較好理解,就不多說了


          4


          cheap

          這是 “cheap(低開銷)” 的 source map,因為它沒有生成列映射(column mapping),只是映射行數(shù) 。
          為了方便演示,我們在代碼加一行錯誤拋出:



          可以看到錯誤信息只有行映射,但實際上開發(fā)時我們有行映射也基本足夠了,所以開發(fā)場景下完全可以使用cheap 模式 ,來節(jié)省sourceMap的開銷




          5


          module

          Webpack會利用loader將所有非js模塊轉(zhuǎn)化為webpack可處理的js模塊,而增加上面的cheap配置后也不會有l(wèi)oader模塊之間對應的sourceMap。

          什么是模塊之間的sourceMap呢?比如jsx文件會經(jīng)歷loader處理成js文件再混淆壓縮, 如果沒有l(wèi)oader之間的sourceMap,那么在debug的時候定義到上圖中的壓縮前的js處,而不能追蹤到jsx中。

          所以為了映射到loader處理前的代碼,我們一般也會加上module配置


          6


          總結(jié)

          1、開發(fā)環(huán)境
          綜上所述,考慮到我們在開發(fā)環(huán)境對sourceMap的要求是:快(eval),信息全(module),且由于此時代碼未壓縮,我們并不那么在意代碼列信息(cheap),所以開發(fā)環(huán)境比較推薦配置:devtool: cheap-module-eval-source-map

          2、生產(chǎn)環(huán)境
          一般情況下,我們并不希望任何人都可以在瀏覽器直接看到我們未編譯的源碼,所以我們不應該直接提供sourceMap給瀏覽器。但我們又需要sourceMap來定位我們的錯誤信息, 這時我們可以設置hidden-source-map
          一方面webpack會生成sourcemap文件以提供給錯誤收集工具比如sentry,另一方面又不會為 bundle 添加引用注釋,以避免瀏覽器使用。
          當然如果沒有這一類的錯誤處理工具,可以看看webpack推薦的其他配置:
          https://www.webpackjs.com/configuration/devtool/

          03


          CSS sourceMap


          說起sourceMap我們第一反應通常是JavaScript的sourceMap,實際上現(xiàn)在css也可以使用sourceMap。因為sourceMap本質(zhì)只是一個json,里面包含了源碼的映射信息。所以其實只要了解sourcemap的編碼規(guī)范,我們可以對任何我們想要的資源生成sourceMap,當然sourceMap 的支持也還是要取決于瀏覽器的支持。

          現(xiàn)在,對于css我們也有同樣訴求,比如我現(xiàn)在打開調(diào)試器看到的樣式配置沒有任何源信息。如果想像js一樣,知道這個css樣式是在哪個文件需要怎么弄呢?

          上面講解的配置其實都是針對js的sourceMap,配置后webpack會自動幫我們生成各類js sourceMap。因為本質(zhì)上webpack只處理js,對于webpack來說,css是否有sourceMap依賴于對css處理的loader是否有sourceMap輸出,所以loader需要開啟并傳遞sourceMap,這樣最后生成的css才會帶上sourceMap 。

          目前使用的css-loader,sass-loader都已經(jīng)提供了生成sourceMap的能力,只需要我們加上配置即可。

          需要注意的是,這里如果要拿到sass編譯前的源碼信息,那么sourceMap一定要從sass-loader一直傳遞到css-loader,中間如有其他loader處理,也要透傳sourceMap


          我們可以看到,加了sourceMap 配置后,sourceMap會被內(nèi)聯(lián)在css代碼里(這一層是css-loader處理的,與你是否使用min-extract-css-plugin抽出css無關)

          加了css sourceMap后,我們可以很輕松的定位到sass編譯前的源碼路徑了。

          通過debug,打印出生成的css sourceMap,和js sourceMap對比并無他樣:

          04


          利用css sourceMap 解決css url resolve的問題


          如果大家用了sass的話,很可能會遇到一個css url resolve的問題,在之前的一篇講webpack 配置的文章里我也提到過:

          實際上,利用css sourceMap這個問題便可以在不改變源碼的情況下就可以完美解決。
          這里會增加一個loader去處理,loader處理流程主要分為二步:
          1、根據(jù)sourceMap的sourcesContent和url內(nèi)容進行匹配,然后從sources定位到原有的css資源路徑
          2、將傳遞給下個loader的url內(nèi)容替換成絕對路徑
          代碼如下:

          1. module.exports = function (content, map) {

          2. ? ?const res = content.replace(/url\((?:\'|")?((\.\/|\.\.\/)+([^\'"\)]*))(\'|")?\)/g, (str, img, p2, imgPath) => {

          3. ? ? ? ?let index = -1;

          4. ? ? ? ?const {sourcesContent = [], sources = [], sourceRoot = []} = map || {};

          5. ? ? ? ?sourcesContent.some((item, i)=> {

          6. ? ? ? ? ? ?if (item.indexOf(img) !== -1) {

          7. ? ? ? ? ? ? ? ?index = i;

          8. ? ? ? ? ? ? ? ?return true;

          9. ? ? ? ? ? ?}

          10. ? ? ? ?});

          11. ? ? ? ?if (index !== -1) {

          12. ? ? ? ? ? ?const dir = path.dirname(sources[index]); // 獲取文件所在目錄

          13. ? ? ? ? ? ?str = str.replace(img, `~${path.join(dir, img)}`);

          14. ? ? ? ?}

          15. ? ? ? ?return str;

          16. ? ?});

          17. ? ?this.callback(null, res, map);

          18. ? ?return;

          19. }

          因為依賴sass-loader 處理之后的sourceMap, 所以@tencent/im-resolve-url-loader應配置在sass-loader 前面,配置如下:

          - END -




          分享前端好文,點亮?在看?


          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  啪啪婷婷五月天 | av麻豆成人电影 AV免费在线网站 AV中文在线观看 A片黄色电影网站 | 在线观看黄a | 国内精品久久久久久久久久久 | 大香蕉日本视频 |