<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知多少:介紹與實(shí)踐

          共 4511字,需瀏覽 10分鐘

           ·

          2020-09-02 06:44


          來(lái)源:?騰訊IMWeb前端團(tuán)隊(duì)

          https://mp.weixin.qq.com/s/j3jVPNgg4WCnI7RBJTxktA

          01


          首先說(shuō)說(shuō)sourceMap


          說(shuō)起sourceMap大家肯定都不陌生,隨著前端工程化的演進(jìn),我們打包出來(lái)的代碼都是混淆壓縮過(guò)的,當(dāng)源代碼經(jīng)過(guò)轉(zhuǎn)換后,調(diào)試就成了一個(gè)問(wèn)題。在瀏覽器中調(diào)試時(shí),如何判斷原始代碼的位置?
          為了解決這個(gè)問(wèn)題,google 提出了sourceMap 的想法,并在chorme上最先支持sourceMap的使用。sourceMap 由于包含許多信息,前期也經(jīng)過(guò)多版的編碼算法優(yōu)化,最后在2011年探索出了Source Map Revision 3.0 ,這個(gè)版本也就是我們現(xiàn)在一直在使用的sourceMap版本。這一版本的mapping信息使用Base64 VLQ 編碼,大大縮小了.map文件的體積。

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

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

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

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

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

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

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

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

          02


          webpack中的sourceMap配置


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


          ???????


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

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

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

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


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


          1


          eval

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

          1)devtool: eval
          我們先看看單獨(dú)的eval配置,這個(gè)配置相對(duì)于其他會(huì)特殊一點(diǎn) 。因?yàn)榕渲美餂](méi)有sourceMap,實(shí)際上它也會(huì)生出map,只是它映射的是轉(zhuǎn)換后的代碼,而不是映射到原始代碼。

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


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


          對(duì)于eval的構(gòu)建模式,我們可以看看官方的描述

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

          可以看出官方是比較推薦開(kāi)發(fā)場(chǎng)景下使用的,因?yàn)樗躢ache sourceMap,從而rebuild的速度會(huì)比較快。


          2


          inline

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


          4


          cheap

          這是 “cheap(低開(kāi)銷)” 的 source map,因?yàn)樗鼪](méi)有生成列映射(column mapping),只是映射行數(shù) 。
          為了方便演示,我們?cè)诖a加一行錯(cuò)誤拋出:

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


          5


          module

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

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

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


          6


          總結(jié)

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

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

          03


          CSS sourceMap


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

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

          上面講解的配置其實(shí)都是針對(duì)js的sourceMap,配置后webpack會(huì)自動(dòng)幫我們生成各類js sourceMap。因?yàn)楸举|(zhì)上webpack只處理js,對(duì)于webpack來(lái)說(shuō),css是否有sourceMap依賴于對(duì)css處理的loader是否有sourceMap輸出,所以loader需要開(kāi)啟并傳遞sourceMap,這樣最后生成的css才會(huì)帶上sourceMap 。

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

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


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

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

          通過(guò)debug,打印出生成的css sourceMap,和js sourceMap對(duì)比并無(wú)他樣:

          04


          利用css sourceMap 解決css url resolve的問(wèn)題


          如果大家用了sass的話,很可能會(huì)遇到一個(gè)css url resolve的問(wèn)題,在之前的一篇講webpack 配置的文章里我也提到過(guò):

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

          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. ? ? ? ? ? ? ? ?returntrue;

          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. }

          因?yàn)橐蕾噑ass-loader 處理之后的sourceMap, 所以@tencent/im-resolve-url-loader應(yīng)配置在sass-loader 前面,配置如下:


          IMWeb 團(tuán)隊(duì)隸屬騰訊公司,是國(guó)內(nèi)最專業(yè)的前端團(tuán)隊(duì)之一。

          我們專注前端領(lǐng)域多年,負(fù)責(zé)過(guò) QQ 資料、QQ 注冊(cè)、QQ 群等億級(jí)業(yè)務(wù)。目前聚焦于在線教育領(lǐng)域,精心打磨?騰訊課堂、企鵝輔導(dǎo)?及 ABCMouse 三大產(chǎn)品。

          》》面試官都在用的題庫(kù),快來(lái)看看《《

          瀏覽 66
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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 | 在线观看免费A片 | 青青草视频免费 | www.黄色网址 |