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

          深入淺出 Source Map

          共 20718字,需瀏覽 42分鐘

           ·

          2023-08-16 21:22

          作者:IDuxFE

          原文:https://juejin.cn/post/7023537118454480904

          專欄地址:前端編譯和工程化[1]**系列文章:Babel 那些事兒[2]一個預(yù)覽 vue 文件 CLI 工具[3]、通過一個“時髦”的例子學(xué) Babel 插件[4]、深入淺出 vue-loader 自定義塊[5]**本文作者:前端小東[6]**

          一、什么是 Source Map

          通俗的來說, Source Map 就是一個信息文件,里面存儲了代碼打包轉(zhuǎn)換后的位置信息,實質(zhì)是一個 json 描述文件,維護(hù)了打包前后的代碼映射關(guān)系。關(guān)于 Source Map 的解釋可以看下 Introduction to JavaScript Source Maps[7]

          我們線上的代碼一般都是經(jīng)過打包的,如果線上代碼報錯了,想要調(diào)試起來,那真是很費勁了,比如下面這個例子:

          使用打包工具 Webpack ,編譯這一段代碼

          console.log('source map!!!')
          console.log(a); //這一行肯定會報錯

          瀏覽器打開后的效果:

          點擊進(jìn)入報錯文件之后:

          這根本沒法找到具體位置以及原因,所以這個時候, Source Map 的作用就來了, Webpack 構(gòu)建代碼中,開啟 Source Map

          然后重新執(zhí)行構(gòu)建,再次打開瀏覽器:

          可以發(fā)現(xiàn),可以成功定位到具體的報錯位置了,這就是 Source Map 的作用。需要注意一點的是, Source Map 并不是 Webpack 特有的,其他打包工具同樣支持 Source Map ,打包工具只是將 Source Map 這項技術(shù)通過配置化的方式引入進(jìn)來。關(guān)于打包工具,下文會有介紹。

          二、Source Map 的作用

          上面的案例只是 Source Map 的初體驗,現(xiàn)在來說一下它的作用,我們?yōu)槭裁葱枰?Source Map ?

          阮一峰老師的JavaScript Source Map 詳解[8]指出,JavaScript 腳本正變得越來越復(fù)雜。大部分源碼(尤其是各種函數(shù)庫和框架)都要經(jīng)過轉(zhuǎn)換,才能投入生產(chǎn)環(huán)境。

          常見的源碼轉(zhuǎn)換,主要是以下三種情況:

          • 壓縮,減小體積
          • 多個文件合并,減少 HTTP 請求數(shù)
          • 其他語言編譯成 JavaScript

          這三種情況,都使得實際運行的代碼不同于開發(fā)代碼,除錯( debug )變得困難重重,所以才需要 Source Map 。結(jié)合上面的例子,即使打包過后的代碼,也可以找到具體的報錯位置,這使得我們 debug 代碼變得輕松簡單,這就是 Source Map 想要解決的問題。

          三、如何生成 Source Map

          各種主流前端任務(wù)管理工具,打包工具都支持生成 Source Map

          3.1 UglifyJS

          UglifyJS 是命令行工具,用于壓縮 JavaScript 代碼

          安裝 UglifyJS

          npm install uglify - js - g

          壓縮代碼的同時生成 Source Map

          uglifyjs app.js - o app.min.js--source - map app.min.js.map

          Source Map 相關(guān)選項:

          --source - map Source Map的文件的路徑和名稱
              --source - map - root 源文件的路徑
              --source - map - url //#sourceMappingURL的路徑。 默認(rèn)為--source-map指定的值。
              --source - map - include - sources 是否將源代碼的內(nèi)容添加到sourcesContent數(shù)組
              --source - map - inline 是否將Source Map寫到壓縮代碼的最后一行
              -- in -source - map 輸入Source Map, 當(dāng)源文件已經(jīng)經(jīng)過變換時使用
          3.2 Grunt

          GruntJavaScript 項目構(gòu)建工具

          配置 grunt-contrib-uglify 插件以生成 Source Map

          grunt.initConfig({
              uglify: {
                  options: {
                      sourceMaptrue
                  }
              }
          });

          使用 grunt-usemin 打包源碼時, grunt-usemin 會依次調(diào)用grunt-contrib-concat[9]grunt-contrib-uglify[10]對源碼進(jìn)行打包和壓縮。因此都需要進(jìn)行配置:

          grunt.initConfig({
              concat: {
                  options: {
                      sourceMaptrue
                  }
              },
              uglify: {
                  options: {
                      sourceMaptrue,
                      sourceMapInfunction(uglifySource{
                          return uglifySource + '.map';
                      },
                  }
              }
          });
          3.3 Gulp

          GulpJavaScript 項目構(gòu)建工具

          使用gulp-sourcemaps[11]生成 Source Map :

          var gulp = require('gulp');
          var plugin1 = require('gulp-plugin1');
          var plugin2 = require('gulp-plugin2');
          var sourcemaps = require('gulp-sourcemaps');

          gulp.task('javascript'function({
              gulp.src('src/**/*.js')
                  .pipe(sourcemaps.init())
                  .pipe(plugin1())
                  .pipe(plugin2())
                  .pipe(sourcemaps.write('../maps'))
                  .pipe(gulp.dest('dist'));
          });
          3.4 SystemJS

          SystemJS 是模塊加載器

          使用SystemJS Build Tool[12]生成 Source Map :

          builder.bundle('myModule.js''outfile.js', {
              minifytrue,
              sourceMapstrue
          });
          • sourceMapContents選項可以指定是否將源碼寫入Source Map文件
          3.5 Webpack

          Webpack 是前端打包工具(本文案例都會使用該打包工具)。在其配置文件 webpack.config.js 中設(shè)置devtool[13]即可生成 Source Map 文件:

          const path = require('path');

          module.exports = {
              entry'./src/index.js',
              output: {
                  filename'bundle.js',
                  path: path.resolve(__dirname, 'dist')
              },
              devtool"source-map"
          };
          • devtool有 20 多種不同取值,分別生成不同類型的Source Map,可以根據(jù)需要進(jìn)行配置。下文會詳細(xì)介紹,這里不再贅述。
          3.6 Closure Compiler

          利用 Closure Compiler[14] 生成

          四、如何使用 Source Map

          生成 Source Map 之后,一般在瀏覽器中調(diào)試使用,前提是需要開啟該功能,以 Chrome 為例:

          打開開發(fā)者工具,找到 Settins

          勾選以下兩個選項:

          再回到上面的案例中,源代碼文件變成了 index.js ,點擊進(jìn)入后顯示真實的源代碼,即說明成功開啟并使用了 Source Map

          五、Source Map 的工作原理

          還是上面這個案例,執(zhí)行打包后,生成 dist 文件夾,打開 dist/bundld.js

          可以看到尾部有這句注釋:

          //# sourceMappingURL=bundle.js.map

          正是因為這句注釋,標(biāo)記了該文件的 Source Map 地址,瀏覽器才可以正確的找到源代碼的位置。 sourceMappingURL 指向 Source Map 文件的 URL 。

          除了這種方式之外,MDN[15]中指出,可以通過 response headerSourceMap: <url> 字段來表明。

          > SourceMap: /path/to/file.js.map

          dist 文件夾中,除了 bundle.js 還有 bundle.js.map ,這個文件才是 Source Map 文件,也是 sourceMappingURL 指向的 URL

          • versionSource map的版本,目前為v3
          • sources:轉(zhuǎn)換前的文件。該項是一個數(shù)組,表示可能存在多個文件合并。
          • names:轉(zhuǎn)換前的所有變量名和屬性名。
          • mappings:記錄位置信息的字符串,下文會介紹。
          • file:轉(zhuǎn)換后的文件名。
          • sourceRoot:轉(zhuǎn)換前的文件所在的目錄。如果與轉(zhuǎn)換前的文件在同一目錄,該項為空。
          • sourcesContent:轉(zhuǎn)換前文件的原始內(nèi)容。
          5.1 關(guān)于Source map的版本

          在2009年 Google 的一篇文章中,在介紹 Cloure Compiler 時, Google 也趁便推出了一款調(diào)試東西: Firefox 插件 Closure Inspector ,以便利調(diào)試編譯后代碼。這便是 Source Map 的初步代啦!

          You can use the compiler with Closure Inspector , a Firebug extension that makes debugging the obfuscated code almost as easy as debugging the human-readable source.

          2010年,在第二代即 Closure Compiler Source Map 2.0 中, Source Map 招認(rèn)了共同的 JSON 格式及其他標(biāo)準(zhǔn),已幾乎具有現(xiàn)在的雛形。最大的差異在于 mapping 算法,也是 Source Map 的要害地址。第二代中的 mapping 已決定運用 base 64 編碼,可是算法同現(xiàn)在有收支,所以生成的 .map 比較現(xiàn)在要大許多。 2011年,第三代即**Source Map Revision 3 Proposal**[16]出爐了,這也是咱們現(xiàn)在運用的 Source Map版別。從文檔的命名看來,此刻的 Source Map 已脫離 Clousre Compiler ,演化成了一款獨立東西,也得到了瀏覽器的支撐。這一版相較于二代最大的改動是 mapping 算法的緊縮換代,運用VLQ[17]編碼生成base64[18]前的 mapping ,大大縮小了 .map 文件的體積。

          Source Map 發(fā)展史的詼諧之處在于,它作為一款輔佐東西被開發(fā)出來。畢竟它輔佐的方針日漸式微,而它卻成為了技能主體,被寫進(jìn)了瀏覽器中。

          Source Map V1最初步生成的Source Map文件大概有轉(zhuǎn)化后文件的10倍大。Source Map V2將之減少了50%,V3又在V2的基礎(chǔ)上減少了50%。所以現(xiàn)在133k的文件對應(yīng)的Source Map文件巨細(xì)大概在300k左右。

          5.2 關(guān)于mappings屬性

          為了避免干擾,將案例改成如下不報錯的情況:

          var a = 1;
          console.log(a);

          打包編譯的后 bundle.js 文件:

          /******/
          (() => { // webpackBootstrap
              var __webpack_exports__ = {};
              /*!**********************!*\
                !*** ./src/index.js ***!
                \**********************/

              var a = 1;
              console.log(a);
              /******/
          })();
          //# sourceMappingURL=bundle.js.map

          打包編譯后的 bundle.js.map 文件:

          {
              "version"3,
              "sources": [
                  "webpack://learn-source-map/./src/index.js"
              ],
              "names": [],
              "mappings""AAAA;AACA,c",
              "file""bundle.js",
              "sourcesContent": [
                  "var a = 1;\r\nconsole.log(a);"
              ],
              "sourceRoot"""
          }

          可以看到 mappings 屬性的值是: AAAA; AACA, c ,要想說清楚這個東西,需要先解釋一下它的組成結(jié)構(gòu)。這是一個字符串,它分成三層:

          • 第一層是行對應(yīng),以分號(; )表示,每個分號對應(yīng)轉(zhuǎn)換后源碼的一行。所以,第一個分號前的內(nèi)容,就對應(yīng)源碼的第一行,以此類推。
          • 第二層是位置對應(yīng),以逗號(, )表示,每個逗號對應(yīng)轉(zhuǎn)換后源碼的一個位置。所以,第一個逗號前的內(nèi)容,就對應(yīng)該行源碼的第一個位置,以此類推。
          • 第三層是位置轉(zhuǎn)換,以VLQ 編碼[19]表示,代表該位置對應(yīng)的轉(zhuǎn)換前的源碼位置。

          在回到源代碼,就可以分析出:

          1. 因為源代碼中有兩行,所以有一個分號,分號前后表示了第一行和第二行。即mappings中的AAAAAACA,c。
          2. 分號后面表示第二行,也就是代碼console.log(a);可以拆分出兩個位置,分別是consolelog(a),所以存在一個逗號。即AACA,c中的AACAc。

          總結(jié),就是轉(zhuǎn)換后的源碼分成兩行,第一行有一個位置,第二行有兩個位置。

          至于這個 AAAAAAcA 等字母是怎么來的,可以參考阮一峰老師的JavaScript Source Map 詳解[20]有作詳細(xì)的介紹。筆者自己的理解是:

          AAAAAAcA 以及 c 都是代表了位置,正常來說,每個位置最多由 5 個字母組成,5 個字母的含義分別是:

          • 第一位,表示這個位置在(轉(zhuǎn)換后的代碼的)的第幾列。
          • 第二位,表示這個位置屬于 sources 屬性中的哪一個文件。
          • 第三位,表示這個位置屬于轉(zhuǎn)換前代碼的第幾行。
          • 第四位,表示這個位置屬于轉(zhuǎn)換前代碼的第幾列。
          • 第五位,表示這個位置屬于 names 屬性中的哪一個變量。

          這里轉(zhuǎn)換后最多只有 4 個字母,是因為沒有 names 屬性。

          每一個位置都可以用VLQ 編碼[21]轉(zhuǎn)換,形成一種映射關(guān)系??梢栽?span style="font-weight: bold;color: rgb(90, 185, 131);">這個網(wǎng)站[22]自己轉(zhuǎn)換測試,將 AAAA; AACA, c 轉(zhuǎn)換后的結(jié)果:

          可以得到兩組數(shù)據(jù):

          [0000]
          [0010], [14]

          數(shù)字都是從 0 開始的,拿位置 AAAA 舉例,轉(zhuǎn)換后得到 [0, 0, 0, 0] ,所以代表的含義分別是;

          1. 壓縮代碼的第一列。
          2. 第一個源代碼文件,即index.js
          3. 源代碼的第一行。
          4. 源代碼第一列

          通過以上解析,我們就能知道源代碼中 var a = 1; 在打包后文件中,即 bundle.js 的具體位置了。

          六、Webpack 中的 Source Map

          上文介紹了 Source Map 的作用,原理等?,F(xiàn)在說一下打包工具 WebPack 中對 Source Map 的應(yīng)用,畢竟我們在開發(fā)中,都離不開它。

          上文有說道,只需要在 webpack.config.js 文件中配置 devtool 就可以使用 Source Map ,這個 devtool 具體的值有哪些,可以參考webpack devtool[23]

          的介紹,官方羅列了 20 幾種類型,我們當(dāng)然不能全部都記住,可以記住幾個關(guān)鍵的:

          建議以下 7 種可選方案:

          • source-map:外部??梢圆榭村e誤代碼準(zhǔn)確信息和源代碼的錯誤位置。
          • inline-source-map:內(nèi)聯(lián)。只生成一個內(nèi)聯(lián) Source Map,可以查看錯誤代碼準(zhǔn)確信息和源代碼的錯誤位置
          • hidden-source-map:外部??梢圆榭村e誤代碼準(zhǔn)確信息,但不能追蹤源代碼錯誤,只能提示到構(gòu)建后代碼的錯誤位置。
          • eval-source-map:內(nèi)聯(lián)。每一個文件都生成對應(yīng)的 Source Map,都在 eval 中,可以查看錯誤代碼準(zhǔn)確信息 和 源代碼的錯誤位置。
          • nosources-source-map:外部??梢圆榭村e誤代碼錯誤原因,但不能查看錯誤代碼準(zhǔn)確信息,并且沒有任何源代碼信息。
          • cheap-source-map:外部??梢圆榭村e誤代碼準(zhǔn)確信息和源代碼的錯誤位置,只能把錯誤精確到整行,忽略列。
          • cheap-module-source-map:外部??梢藻e誤代碼準(zhǔn)確信息和源代碼的錯誤位置,module 會加入 loaderSource Map。

          內(nèi)聯(lián)和外部的區(qū)別:

          1. 外部生成了文件(.map),內(nèi)聯(lián)沒有。
          2. 內(nèi)聯(lián)構(gòu)建速度更快。

          以下通過具體的案例演示上面的 7 種類型:

          首先,將案例改成報錯狀態(tài),為了體現(xiàn)列的情況,將源代碼修改成如下:

          console.log('source map!!!')
          var a = 1;
          console.log(a, b); //這一行肯定會報錯
          6.1 source-map
          devtool: 'source-map'

          編譯后,可以查看錯誤代碼準(zhǔn)確信息和源代碼的錯誤位置

          生成了 .map 文件:

          6.2 inline-source-map
          devtool: 'inline-source-map'

          編譯后,可以查看錯誤代碼準(zhǔn)確信息和源代碼的錯誤位置

          但是沒有生成 .map文件 ,而是以 base64 的形式插入到 sourceMappingURL 中:

          6.3 hidden-source-map
          devtool: 'hidden-source-map'

          編譯后,可以查看錯誤代碼準(zhǔn)確信息,但是無法查看源代碼的位置

          生成了 .map 文件:

          6.4 eval-source-map
          devtool: 'eval-source-map'

          編譯后,可以查看錯誤代碼準(zhǔn)確信息和源代碼的錯誤位置

          但是沒有生成 .map文件 ,而是在 eval函數(shù) 中,包括 sourceMappingURL :

          6.5 nosources-source-map
          devtool: 'nosources-source-map'

          編譯后,可以查看無法查看錯誤代碼的準(zhǔn)確位置和源代碼的錯誤位置,只能提示錯誤原因

          生成了 .map 文件:

          6.6 cheap-source-map
          devtool: 'cheap-source-map'

          編譯后,可以查看錯誤代碼準(zhǔn)確信息和源代碼的錯誤位置,但是忽略了具體的列( 因為是b導(dǎo)致報錯

          生成了 .map 文件:

          6.7 cheap-module-source-map

          因為需要 module ,所以案例中增加 loader

          module: {
              rules: [{
                  test/\.css$/,
                  use: [
                      // style-loader:創(chuàng)建style標(biāo)簽,將js中的樣式資源插入進(jìn)去,添加到head中生效
                      'style-loader',
                      // css-loader:將css文件變成commonjs模塊加載到j(luò)s中,里面內(nèi)容是樣式字符串
                      'css-loader'
                  ]
              }]
          }

          src 目錄下新建 index.css 文件,添加樣式代碼:

          body {
              margin0;
              padding0;
              height100%;
              background-color: pink;
          }

          然后在 src/index.js 中引入 index.css

          //引入index.css
          import './index.css';

          console.log('source map!!!')
          var a = 1;
          console.log(a, b); //這一行肯定會報錯

          修改 devtool

          devtool: 'cheap-module-source-map'

          打包后,打開瀏覽器,樣式生效,說明 loader 引入成功。可以查看錯誤代碼準(zhǔn)確信息和源代碼的錯誤位置,但是忽略了具體的列( 因為是b導(dǎo)致報錯

          生成了 .map 文件,同時,將 loader 的信息也一起打包進(jìn)來:

          6.8 總結(jié)

          (1)開發(fā)環(huán)境:需要考慮速度快,調(diào)試更友好

          • 速度快( eval > inline > cheap >... )

            1. eval-cheap-souce-map
            2. eval-source-map
          • 調(diào)試更友好

            1. souce-map
            2. cheap-module-souce-map
            3. cheap-souce-map

          最終得出最好的兩種方案 --> eval-source-map(完整度高,內(nèi)聯(lián)速度快) / eval-cheap-module-souce-map(錯誤提示忽略列但是包含其他信息,內(nèi)聯(lián)速度快)

          (2)生產(chǎn)環(huán)境:需要考慮源代碼要不要隱藏,調(diào)試要不要更友好

          • 內(nèi)聯(lián)會讓代碼體積變大,所以在生產(chǎn)環(huán)境不用內(nèi)聯(lián)

          • 隱藏源代碼

            1. nosources-source-map 全部隱藏(打包后的代碼與源代碼)
            2. hidden-source-map 只隱藏源代碼,會提示構(gòu)建后代碼錯誤信息

          最終得出最好的兩種方案 --> source-map(最完整) / cheap-module-souce-map(錯誤提示一整行忽略列)

          七、總結(jié)

          Source Map 是我們?nèi)粘i_發(fā)過程中必不可少的,它可以幫助我們調(diào)試,定位錯誤。盡管它涉及非常多的知識點,例如:VLQ[24]、base64[25]等,但是我們核心關(guān)注的是它的工作原理,以及在打包工具中,如 webpack 等對 Source Map 的應(yīng)用。

          Source Map 非常強大,不僅在應(yīng)用于日常開發(fā),還可以做更多的事情,如 性能異常監(jiān)控平臺 。比如FunDebug[26]這個網(wǎng)站就是通過 Source Map 還原生產(chǎn)環(huán)境中的壓縮代碼,提供完整的堆棧信息,準(zhǔn)確定位出錯誤源碼,幫助用戶快速修復(fù) Bug ,像這樣的案例還有許多。

          總之,學(xué)習(xí) Source Map 是非常有必要的。

          八、參考

          • Introduction to JavaScript Source Maps[27]
          • MDN[28]
          • JavaScript Source Map 詳解[29]
          • VLQ[30]
          • base64[31]
          • base64vlq[32]
          • FunDebug[33]
          • 絕了,沒想到一個 source map 居然涉及到那么多知識盲區(qū)[34]
          • 談?wù)勎沂侨绾潍@得知乎的前端源碼的[35]

          參考資料

          [1]

          https://juejin.cn/column/6992030342987120677: https://juejin.cn/column/6992030342987120677

          [2]

          https://juejin.cn/post/6992371845349507108: https://juejin.cn/post/6992371845349507108

          [3]

          https://juejin.cn/post/7005351791671902244: https://juejin.cn/post/7005351791671902244

          [4]

          https://juejin.cn/post/7013149595068792845: https://juejin.cn/post/7013149595068792845

          [5]

          https://juejin.cn/post/7021687704999952415: https://juejin.cn/post/7021687704999952415

          [6]

          https://juejin.cn/user/932815872994359: https://juejin.cn/user/932815872994359

          [7]

          https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/: https://link.juejin.cn?target=https%3A%2F%2Fwww.html5rocks.com%2Fen%2Ftutorials%2Fdevelopertools%2Fsourcemaps%2F

          [8]

          http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html: https://link.juejin.cn?target=http%3A%2F%2Fwww.ruanyifeng.com%2Fblog%2F2013%2F01%2Fjavascript_source_map.html

          [9]

          https://github.com/gruntjs/grunt-contrib-concat: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fgruntjs%2Fgrunt-contrib-concat

          [10]

          https://github.com/gruntjs/grunt-contrib-uglify: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fgruntjs%2Fgrunt-contrib-uglify

          [11]

          https://github.com/floridoo/gulp-sourcemaps: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Ffloridoo%2Fgulp-sourcemaps

          [12]

          https://github.com/systemjs/builder: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fsystemjs%2Fbuilder

          [13]

          https://webpack.js.org/configuration/devtool/: https://link.juejin.cn?target=https%3A%2F%2Fwebpack.js.org%2Fconfiguration%2Fdevtool%2F

          [14]

          https://github.com/google/closure-compiler: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fgoogle%2Fclosure-compiler

          [15]

          https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/SourceMap: https://link.juejin.cn?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FHTTP%2FHeaders%2FSourceMap

          [16]

          https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#: https://link.juejin.cn?target=https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k%2Fedit%23

          [17]

          https://en.wikipedia.org/wiki/Variable-length_quantity: https://link.juejin.cn?target=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FVariable-length_quantity

          [18]

          https://zh.wikipedia.org/zh-cn/Base64: https://link.juejin.cn?target=https%3A%2F%2Fzh.wikipedia.org%2Fzh-cn%2FBase64

          [19]

          https://en.wikipedia.org/wiki/Variable-length_quantity: https://link.juejin.cn?target=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FVariable-length_quantity

          [20]

          http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html: https://link.juejin.cn?target=http%3A%2F%2Fwww.ruanyifeng.com%2Fblog%2F2013%2F01%2Fjavascript_source_map.html

          [21]

          https://en.wikipedia.org/wiki/Variable-length_quantity: https://link.juejin.cn?target=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FVariable-length_quantity

          [22]

          https://www.murzwin.com/base64vlq.html: https://link.juejin.cn?target=https%3A%2F%2Fwww.murzwin.com%2Fbase64vlq.html

          [23]

          https://webpack.docschina.org/configuration/devtool/#root: https://link.juejin.cn?target=https%3A%2F%2Fwebpack.docschina.org%2Fconfiguration%2Fdevtool%2F%23root

          [24]

          https://en.wikipedia.org/wiki/Variable-length_quantity: https://link.juejin.cn?target=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FVariable-length_quantity

          [25]

          https://zh.wikipedia.org/zh-cn/Base64: https://link.juejin.cn?target=https%3A%2F%2Fzh.wikipedia.org%2Fzh-cn%2FBase64

          [26]

          https://www.fundebug.com/: https://link.juejin.cn?target=https%3A%2F%2Fwww.fundebug.com%2F

          [27]

          https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/: https://link.juejin.cn?target=https%3A%2F%2Fwww.html5rocks.com%2Fen%2Ftutorials%2Fdevelopertools%2Fsourcemaps%2F

          [28]

          https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/SourceMap: https://link.juejin.cn?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FHTTP%2FHeaders%2FSourceMap

          [29]

          http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html: https://link.juejin.cn?target=http%3A%2F%2Fwww.ruanyifeng.com%2Fblog%2F2013%2F01%2Fjavascript_source_map.html

          [30]

          https://en.wikipedia.org/wiki/Variable-length_quantity: https://link.juejin.cn?target=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FVariable-length_quantity

          [31]

          https://zh.wikipedia.org/zh-cn/Base64: https://link.juejin.cn?target=https%3A%2F%2Fzh.wikipedia.org%2Fzh-cn%2FBase64

          [32]

          https://www.murzwin.com/base64vlq.html: https://link.juejin.cn?target=https%3A%2F%2Fwww.murzwin.com%2Fbase64vlq.html

          [33]

          https://www.fundebug.com/: https://link.juejin.cn?target=https%3A%2F%2Fwww.fundebug.com%2F

          [34]

          https://juejin.cn/post/6963076475020902436: https://juejin.cn/post/6963076475020902436

          [35]

          https://zhuanlan.zhihu.com/p/26033573: https://link.juejin.cn?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F26033573

          最后



          如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我個小忙:

          1. 點個「喜歡」或「在看」,讓更多的人也能看到這篇內(nèi)容

          2. 我組建了個氛圍非常好的前端群,里面有很多前端小伙伴,歡迎加我微信「sherlocked_93」拉你加群,一起交流和學(xué)習(xí)

          3. 關(guān)注公眾號「前端下午茶」,持續(xù)為你推送精選好文,也可以加我為好友,隨時聊騷。



          點個喜歡支持我吧,在看就更好了


          瀏覽 265
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  啪啪黄色视频 | 国产美女a级 | 亚洲网站在线免费观看 | AA片免费看 | 久久视频高清无码 |