资讯专栏INFORMATION COLUMN

Source Map入门教程

archieyang / 502人阅读

摘要:多个文件合并,减少请求数。生成的多了,表示文件的位置。转换前的所有变量名和属性名。自从年双十一正式上线,累计处理了亿错误事件,得到了金山软件等众多知名用户的认可。

部署前端之前,开发者通常会对代码进行打包压缩,这样可以减少代码大小,从而有效提高访问速度。然而,压缩代码的报错信息是很难Debug的,因为它的行号和列号已经失真。这时就需要Source Map来还原真实的出错位置了。

为啥变换代码?

前端代码越来越复杂的情况下,开发者通常会使用webpack、UglifyJS2等工具对代码进行打包变换,这样可以减少代码大小,有效提高访问速度。关于变换代码的原因,这里不妨引用一下大神阮一峰的JavaScript Source Map 详解:

压缩,减小体积。比如jQuery 1.9的源码,压缩前是252KB,压缩后是32KB。

多个文件合并,减少HTTP请求数。

其他语言编译成JavaScript。最常见的例子就是CoffeeScript。

如何变换代码?

下面是一个简单的“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:///Users/fundebug/sourcemap-tutorial/hello.js:4:9
    <匿名> file:///Users/fundebug/sourcemap-tutorial/hello.js:8:1

hello.min.js的报错信息是这样:

ReferenceError: Name is not defined
    o file:///Users/fundebug/sourcemap-tutorial/hello.min.js:1:18
    <匿名> file:///Users/fundebug/sourcemap-tutorial/hello.min.js:1:59

对比压缩前后的出错信息,我们会发现,错误行号和列号已经失真,且函数名也经过了变换。而对于真实的前端项目,开发者会将数十个源文件压缩为一个文件,这时,错误的列号可能多达数千,且出错的真实文件名也是很难确定的,这样的话,压缩代码的报错信息是很难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();
//# sourceMappingURL=hello.min.js.map

生成的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()
{
    var name = "Fundebug";
    var greeting = "Hello, " + Name;
    console.log(greeting);
}

sayHello();
"]
}

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


    

使用Chrome打开hello.min.html,在控制台看到的错误如下:

Uncaught ReferenceError: Name is not defined
    at o (hello.min.js:1)
    at hello.min.js:1

报错的文件仍然为hello.min.js,需要刷新一下Source Map才有作用:

Uncaught ReferenceError: Name is not defined
    at o (hello.js:4)
    at hello.js:8

注意,Chrome的报错信息没有列号,因此4为错误的行号。Chrome不仅可以通过Source Map还原真实的出错位置,还可以根据Source Map的sourcesContent还原出错的源代码。点击出错位置,即可跳转到源码,这样Debug将非常方便。

参考链接

JavaScript Source Map 详解

Source Map Revision 3 Proposal

How to enable source maps

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了6亿+错误事件,得到了Google、360、金山软件等众多知名用户的认可。欢迎免费试用!

版权声明

转载时请注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2017/03/13/sourcemap-tutorial/

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86949.html

相关文章

  • [Webpack并不难]使用教程(一)--- entry,devtool,output,resol

    摘要:这是局部安装局部安装的使用要带路径哇,要写路径,好麻烦哦,没事,那就全局安装吧。如果该值是一个相对路径,它将相对于包含的文件。就相当于就相当于就相当于后面带有意味着要完全匹配如果,因为没完全匹配,那么加载的是下文件夹里的使用教程二 Webpack是什么,我就不过多介绍了,大家都有耳闻,不过还是配张图让大家体会下。showImg(https://segmentfault.com/img/...

    wudengzan 评论0 收藏0
  • babel6 入门-配置安装使用_byKL

    摘要:入门什么是是一个广泛使用的转码器,可以将代码转为代码,从而在现有环境执行。 babel6 入门 什么是babel Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。 因为es6比es5的代码更为适合编写程序,但是因为历史的原因,现在普遍的浏览器并不支持es6代码(普遍支持es5),即如果你写es6代码之后,在浏览器上运行出错,因为浏览器的javas...

    qianfeng 评论0 收藏0
  • webpack4详细教程,从无到有搭建react脚手架(四)

    摘要:相关链接详细教程,从无到有搭建脚手架一详细教程,从无到有搭建脚手架二详细教程,从无到有搭建脚手架三管理打包后目录结构打包结构如下修改配置通过相对目录对资源命名前加上目录名,效果后面的步骤在这里需要安装一个大型的包,以为例安装为第三 相关链接 webpack4详细教程,从无到有搭建react脚手架(一) webpack4详细教程,从无到有搭建react脚手架(二) webpack4详细...

    chnmagnus 评论0 收藏0
  • webpack -> vue Component 从入门到放弃(四)

    摘要:先展示一下文件目录结构先把相关的依赖给装好注意一下注释只是为了解释,在中不能写注释插件加载器预编译语法跨平台环境用来设置命令行安装预编译语法的配置中的对象,用于处理目录的对象,提高开发效率。 Foreword 之前三篇大致介绍了webpack的用法,正如这个系列标题而言 从webpack 到 vue Component,所以最后一篇文章当然是要讲 component, 不对应该说是结合...

    z2xy 评论0 收藏0
  • webpack -> vue Component 从入门到放弃(四)

    摘要:先展示一下文件目录结构先把相关的依赖给装好注意一下注释只是为了解释,在中不能写注释插件加载器预编译语法跨平台环境用来设置命令行安装预编译语法的配置中的对象,用于处理目录的对象,提高开发效率。 Foreword 之前三篇大致介绍了webpack的用法,正如这个系列标题而言 从webpack 到 vue Component,所以最后一篇文章当然是要讲 component, 不对应该说是结合...

    MycLambert 评论0 收藏0

发表评论

0条评论

archieyang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<