We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
早些时候, 读阮一峰的一篇关于sourceMap的文章, 我还记得那个时候, 刚刚接触webpack吧, 头发还很多, 接触一个webpack的属性devtool, 那个时候的webpack汉化还不是很好, 看着一个个eval, cheap-eval-source-map等等的属性, 一头雾水, 半知半解.
eval, cheap-eval-source-map
现在回头再看webpack的官方文档, 恍然大悟, 原来是真的不懂!
webpack
我们用webpack打包, 生成的隐射文件一般有几种方式
罗列了这么多的选项, 但是其中的关键字, 其实可以归纳为以下几个
eval, 使用eval函数包裹整个模块, 并且在文件开始或末尾添加// sourceUrl=xxx的方式.这种方式也可以生成sourceMap, 但是实现是基于浏览器的runtime的, 也就是说我们如果拿到报错的信息, 但是却拿不到source map的文件, 很难去做错误回溯, 同时因为隐射的是转译后的代码, error trace的行号是不准确的, 同时source map的实现基于浏览器, 兼容性和一致性不敢保证, 在生产环境中一般不会使用.
eval
// sourceUrl=xxx
source-map,生成.map文件的格式, 并且在源文件结尾添加// sourceMappingUrl=xxx.map的方式. 这种方式可以根据堆栈信息去回溯错误, 并且准确定位行和列.
source-map
// sourceMappingUrl=xxx.map
cheap, 不在隐射文件中生成列对应信息, 因此只能定位行
cheap
module, 不加载loader的sourceMap, 意味着如果有babel等loader, debugger的时候只能看到转译后的代码
module
inline, 以dataUrl的方式把隐射的信息添加在文件的末尾, 这里inline属性是用在第三方工具使用, 不适合在开发环境或者生产环境使用, 原因是inline会把当前文件的sourceContent都包含进来, 在生成环境下,会加载模块文件的体积, 开发环境下rebuild的速度又慢.
inline
hidden, 意味着不会在源文件的末尾添加注释, 表明source map的文件地址, 同时webpack建议我们不上传source map源文件到服务器, 而是自己另外储存, 在堆栈检查工具中使用.
hidden
nosources, 生成的source map没有源码信息,所以不会公布源代码, 但是会反编译文件名和目录结构, 这需要上传source map文件到服务器.
nosources
在以上的几点介绍中, 或多或少的理解了各种的组合的作用和优势, 值得一说的eval的方式生成的source map和我们uglifyJs或者terser生成的不一样, eval的方法生成source map, 是需要使用eval()包含着运行的代码, 在代码的最后标注// sourceUrl=xxx.js, 这在浏览器内部的运行时
eval()
// sourceUrl=xxx.js
devtool: 'sourcemap'
比如:
class A { constructor(a, b) { this.a = a; this.b = b; } } debugger; throw Error('test source map locate'); let a = new A(1, 2); console.log(a.a);
devtool: 'sourcemap', 情况下,调试和错误堆栈结果:
debugger和错误的堆栈信息都能正确定位, debugger的是babel转译前的代码.
devtool: 'cheap-module-eval-source-map'
devtool: 'cheap-module-eval-source-map'的例子, 则是包括eval, 和sourcemap 2中混合的source map方式, 也即是说生成隐射文件, 既包括eval的base64, 又有xxx.map的map文件, 同时cheap没有列号,module意味着会加载loader的source map信息, 可以看到转译前的代码
sourcemap
相同的代码
webpack 的devtool 属性差不多了, inline, 和nosource, hidden属性用的比较少, 就不细说了.
生产环境推荐的使用source-map,特点不增加模块文件的大小, 同时error trace 准确,开发环境推荐使用cheap-module-eval-source-map, rebuild的速度快, 可以定位问题的位置, 追溯到未转译前的代码.
cheap-module-eval-source-map
可以完整的输出转移前代码的行号和列号, 但是代价是重复编译的速度比较慢.
打包出来的xxx.map文件的就是隐射到的文件
xxx.map
let sourceCodeHere = xxxx //# sourceMappingURL=0.787d0614320f767fc8d1.js.map //=>0.787d0614320f767fc8d1.js.map { "version": 3, "sources":[ "webpack:///./node_modules/lodash/_listCacheHas.js", "webpack:///./node_modules/sockjs-client/lib/transport/jsonp-polling .js", "webpack:///./node_modules/lodash/_cloneArrayBuffer.js" ], "names": ["assocIndexOf", "module", "exports"], "mappings": ";gFAAA,IAAIA,EAAe,EAAQ,QAe3BC,EAAOC,QAJP,SAAsBC,..." }
.map
mappings 里面储存的是隐射信息, 也是整个文件的大小的瓶颈, 如何设置一个合理和具有效率的编码去表示对源码的一对一隐射, 对整个map文件的大小具有重大的意义.
对于mappings字段的解读
一个片段具有5个字符
所以在这里引入MIDI文件的VLQ编码.
VLQ编码是Variable-length quantity 的全称,使用任意数量的8bit去表示一个较大的数值, 是一种变长的编码方式, 也就是说需要一个控制位去控制当前的编码单元是否是一个有效的整体,能够单独的表达一个数值.
Variable-length quantity
实际用到了source map的场景下, 就具体到使用任意数量的6bit去表示一个数值. 一个6bit的单元, 可以表示-15 ~ +15 的范围, 具体的字符隐射, 可以借用base64的编码字符集
base64的编码字符集隐射表.
所以,隐射的情况下, 解读mappings的一个片段, 如QAAA, 在隐射表里面表示16,0,0,0.
QAAA
16,0,0,0
二进制010000,000000,000000,000000.
010000
000000
所以这里表示, 表示编译后文件的第8列, 位于源码的第0个文件, 第0行0列, names里面的第0个变量.
23 用数值表示 10111,
23
0001 0111
0111
1 0111 1
0001
000001
最好查表得结果47,1=>vB.
47,1=>vB
https://survivejs.com/webpack/building/source-maps/ http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html http://www.alloyteam.com/2014/01/source-map-version-3-introduction/
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
早些时候, 读阮一峰的一篇关于sourceMap的文章, 我还记得那个时候, 刚刚接触webpack吧, 头发还很多, 接触一个webpack的属性devtool, 那个时候的webpack汉化还不是很好, 看着一个个
eval, cheap-eval-source-map
等等的属性, 一头雾水, 半知半解.现在回头再看webpack的官方文档, 恍然大悟, 原来是真的不懂!
webpack
的devtool属性我们用webpack打包, 生成的隐射文件一般有几种方式
罗列了这么多的选项, 但是其中的关键字, 其实可以归纳为以下几个
eval
, 使用eval函数包裹整个模块, 并且在文件开始或末尾添加// sourceUrl=xxx
的方式.这种方式也可以生成sourceMap, 但是实现是基于浏览器的runtime的, 也就是说我们如果拿到报错的信息, 但是却拿不到source map的文件, 很难去做错误回溯, 同时因为隐射的是转译后的代码, error trace的行号是不准确的, 同时source map的实现基于浏览器, 兼容性和一致性不敢保证, 在生产环境中一般不会使用.source-map
,生成.map文件的格式, 并且在源文件结尾添加// sourceMappingUrl=xxx.map
的方式. 这种方式可以根据堆栈信息去回溯错误, 并且准确定位行和列.cheap
, 不在隐射文件中生成列对应信息, 因此只能定位行module
, 不加载loader的sourceMap, 意味着如果有babel等loader, debugger的时候只能看到转译后的代码inline
, 以dataUrl的方式把隐射的信息添加在文件的末尾, 这里inline属性是用在第三方工具使用, 不适合在开发环境或者生产环境使用, 原因是inline会把当前文件的sourceContent都包含进来, 在生成环境下,会加载模块文件的体积, 开发环境下rebuild的速度又慢.hidden
, 意味着不会在源文件的末尾添加注释, 表明source map的文件地址, 同时webpack建议我们不上传source map源文件到服务器, 而是自己另外储存, 在堆栈检查工具中使用.nosources
, 生成的source map没有源码信息,所以不会公布源代码, 但是会反编译文件名和目录结构, 这需要上传source map文件到服务器.在以上的几点介绍中, 或多或少的理解了各种的组合的作用和优势, 值得一说的eval的方式生成的source map和我们uglifyJs或者terser生成的不一样, eval的方法生成source map, 是需要使用
eval()
包含着运行的代码, 在代码的最后标注// sourceUrl=xxx.js
, 这在浏览器内部的运行时devtool: 'sourcemap'
的例子比如:
devtool: 'sourcemap'
, 情况下,调试和错误堆栈结果:debugger和错误的堆栈信息都能正确定位, debugger的是babel转译前的代码.
devtool: 'cheap-module-eval-source-map'
的例子devtool: 'cheap-module-eval-source-map'
的例子, 则是包括eval
, 和sourcemap
2中混合的source map方式, 也即是说生成隐射文件, 既包括eval的base64, 又有xxx.map的map文件, 同时cheap
没有列号,module
意味着会加载loader的source map信息, 可以看到转译前的代码相同的代码
devtool 小结
webpack 的devtool 属性差不多了, inline, 和nosource, hidden属性用的比较少, 就不细说了.
生产环境推荐的使用
source-map
,特点不增加模块文件的大小, 同时error trace 准确,开发环境推荐使用cheap-module-eval-source-map
, rebuild的速度快, 可以定位问题的位置, 追溯到未转译前的代码.可以完整的输出转移前代码的行号和列号, 但是代价是重复编译的速度比较慢.
认识source map文件的内容
打包出来的
xxx.map
文件的就是隐射到的文件.map
文件主要由几个字段组成mappings 里面储存的是隐射信息, 也是整个文件的大小的瓶颈, 如何设置一个合理和具有效率的编码去表示对源码的一对一隐射, 对整个map文件的大小具有重大的意义.
对于mappings字段的解读
一个片段具有5个字符

所以在这里引入MIDI文件的VLQ编码.
VLQ 编码
VLQ编码是
Variable-length quantity
的全称,使用任意数量的8bit去表示一个较大的数值, 是一种变长的编码方式, 也就是说需要一个控制位去控制当前的编码单元是否是一个有效的整体,能够单独的表达一个数值.实际用到了source map的场景下, 就具体到使用任意数量的6bit去表示一个数值.

一个6bit的单元, 可以表示-15 ~ +15 的范围, 具体的字符隐射, 可以借用base64的编码字符集
base64的编码字符集隐射表.

所以,隐射的情况下, 解读mappings的一个片段, 如
QAAA
, 在隐射表里面表示16,0,0,0
.二进制
010000
,000000
,000000
,000000
.所以这里表示, 表示编译后文件的第8列, 位于源码的第0个文件, 第0行0列, names里面的第0个变量.
如何用VLQ编码表示-23
23
用数值表示 10111,0001 0111
.0111
=>1 0111 1
, 连续符号位为1, 标志位为1, 表负数, 接着高位0001
=>000001
, 连续符号位为0, 没有标志位.最好查表得结果
47,1=>vB
.参考
The text was updated successfully, but these errors were encountered: