部署前端之前,开发者通常会对代码进行打包压缩,这样可以减少代码大小,从而有效提高访问速度。然而,压缩代码的报错信息是很难Debug的,因为它的行号和列号已经失真。这时就需要Source Map来还原真实的出错位置了。
为啥变换代码?
前端代码越来越复杂的情况下,开发者通常会使用webpack、UglifyJS2等工具对代码进行打包变换,这样可以减少代码大小,有效提高访问速度。关于变换代码的原因,这里不妨引用一下大神阮一峰的JavaScript Source Map 详解:
如何变换代码?
下面是一个简单的“hello World”程序
hello.js
function sayHello ()
{
var name = "Fundebug" ;
var greeting = "Hello, " + Name;
console .log(greeting);
}
sayHello();
使用UglifyJS2对源代码进行压缩变换:
uglifyjs hello.js \
-m toplevel=true \
-c unused=true ,collapse_vars=true \
-o hello.min.js
压缩后的代码
hello.min.js
function o () {var o="Hello, " +Name;console .log(o)}o();
为啥需要Source Map?
使用Firefox执行
hello.js
的报错信息是这样:
ReferenceError : Name is not defined
sayHello file:
file:
而
hello.min.js
的报错信息是这样:
ReferenceError : Name is not defined
o file:
file:
对比压缩前后的出错信息,我们会发现,错误行号和列号已经失真,且函数名也经过了变换。而对于真实的前端项目,开发者会将数十个源文件压缩为一个文件,这时,错误的列号可能多达数千,且出错的真实文件名也是很难确定的,这样的话,压缩代码的报错信息是很难Debug的。
而Source Map则可以用于还原真实的出错位置
,帮助开发者更快的Debug。
什么是Source Map?
使用UglifyJS2时指定source-map选项即可生成Source Map:
uglifyjs hello.js \
-m toplevel=true \
-c unused=true ,collapse_vars=true \
--source -map hello.min.js.map \
--source -map-include-sources \
--source -map-root \
-o hello.min.js
各种主流前端任务管理工具,打包工具都支持生成Source Map,具体可以查看生成Source Map - Fundebug文档。
生成的
hello.min.js
多了sourceMappingURL,表示Source Map文件的位置。
function o () {var o="Hello, " +Name;console .log(o)}o();
生成的Source Map为
hello.min.js.map
:
{
"version" : 3 ,
"sources" : ["hello.js" ],
"names" : ["sayHello" , "greeting" , "Name" , "console" , "log" ],
"mappings" : "AAAA,QAASA,KAEL,GACIC,GAAW,UAAYC,IAC3BC,SAAQC,IAAIH,GAGhBD" ,
"file" : "hello.min.js" ,
"sourceRoot" : "" ,
"sourcesContent" : ["function sayHello()\n{\n var name = \"Fundebug\";\n var greeting = \"Hello, \" + Name;\n console.log(greeting);\n}\n\nsayHello();\n" ]
}
由
hello.min.js.map
可知,Source Map是一个JSON文件,而它
包含了代码转换前后的位置信息
。也就是说,给定一个转换之后的压缩代码的位置,就可以通过Source Map获取转换之前的代码位置,反过来也一样。Source Map各个属性的含义如下:
version:Source Map的版本号。
sources:转换前的文件列表。
names:转换前的所有变量名和属性名。
mappings:记录位置信息的字符串,经过编码。
file:(可选)转换后的文件名。
sourceRoot:(可选)转换前的文件所在的目录。如果与转换前的文件在同一目录,该项为空。
sourcesContent:(可选)转换前的文件内容列表,与sources列表依次对应。
Source Map真正神奇之处在于mappings属性,它记录了位置是如何对应的。JavaScript Source Map 详解已经有很好的解释,这里不再赘述。
怎样使用Source Map?
主流浏览器均支持Source Map功能,不过Chrome与Firefox需要一些简单的配置,具体步骤请参考How to enable source maps。下面以MacBook上的Chrome浏览器为例,介绍一下配置方法:
1. 开启
开发者工具
使用快捷键
option + command + i
;或者在菜单栏选择
视图->开发者->开发者工具
2. 打开设置
使用快捷键
fn + F1
;或者点击右上角的三个点的图标,选择Settings
3. 开启Source Map
在Sources中,选中
Enable JavaScript source maps
为了测试,我写了一个简单的HTML文件
hello.min.html