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

为啥变换代码?

前端代码越来越复杂的情况下,开发者通常会使用webpackUglifyJS2等工具对代码进行打包变换,这样可以减少代码大小,有效提高访问速度。关于变换代码的原因,这里不妨引用一下大神阮一峰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()\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

<head>
    <script type="text/javascript" src="hello.min.js"></script>
</head>

使用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将非常方便。

 

参考链接

Source Map入门教程的更多相关文章

  1. Fundebug微信小程序BUG监控服务支持Source Map

    摘要: 自动还原真实出错位置,快速修复BUG. Source Map功能 微信小程序的Source Map功能目前只在 iOS 6.7.2 及以上版本支持. 微信小程序在打包时,会将所有 js 代码打 ...

  2. Groovy入门教程

    Groovy入门教程 kmyhy@126.com  2009-5-13 一.groovy是什么 简单地说,Groovy 是下一代的java语言,跟java一样,它也运行在 JVM 中. 作为跑在JVM ...

  3. webpack1 新手入门教程

    本文github仓库地址: https://github.com/Rynxiao/webpack-tutorial ,里面包括了本教程的所有代码. [如果你觉得这篇文章写得不错,麻烦给本仓库一颗星:- ...

  4. react 入门教程 阮一峰老师真的是榜样

    -  转自阮一峰老师博客 React 入门实例教程   作者: 阮一峰 日期: 2015年3月31日 现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Nati ...

  5. openlayers3入门教程

                                                                                                        ...

  6. OpenLayers 3 入门教程

    OpenLayers 3 入门教程摘要OpenLayers 3对OpenLayers网络地图库进行了根本的重新设计.版本2虽然被广泛使用,但从JavaScript开发的早期发展阶段开始,已日益现实出它 ...

  7. abp学习(四)——根据入门教程(aspnetMVC Web API进一步学习)

    Introduction With AspNet MVC Web API EntityFramework and AngularJS 地址:https://aspnetboilerplate.com/ ...

  8. 《JavaScript语言入门教程》记录整理:面向对象

    目录 面向对象编程 实例对象与 new 命令 this关键字 对象的继承 Object对象的方法 严格模式(strict mode) 本系列基于阮一峰老师的<JavaScrip语言入门教程> ...

  9. 要web开发精品教程吗?免费无广告一百期连讲的那种-逐浪CMS前端开发100期入门教程全面开放

    要web开发精品教程吗?免费无广告一百期连讲的那种-逐浪CMS前端开发100期入门教程全面开放 大师主讲 经验难得 由逐浪CMS首席架构师发哥老师,亲自主理讲解. 历时一年精心打造, 汇聚了互联网诞生 ...

随机推荐

  1. easyUI resizable组件使用

    easyUI resizable组件使用: <!DOCTYPE html> <html lang="en"> <head> <meta c ...

  2. Linux内存管理之slab分配器

    slab分配器是什么? 参考:http://blog.csdn.net/vanbreaker/article/details/7664296 slab分配器是Linux内存管理中非常重要和复杂的一部分 ...

  3. SSM(Maven集成)

    ssm全称:Spring+SpringMVC+Mybatis ssm简介: 1.Spring Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod J ...

  4. ArcGIS 网络分析[1] 介绍与博文目录【更新中】

    网络分析是个热点,理论上是属于计算机图形学和数据结构的,GIS以此为基础做出应用. 以下列举本人在学习中遇到的网络分析问题与经验总结. 平台:Windows 10操作系统,ArcGIS for Des ...

  5. [css]《css揭秘》学习(三)-灵活的背景定位

    一.background-position属性 使用该属性,在不确定容器大小的情况下,也可以指定图案距离容器边缘的位置:但是需要为不支持该属性的浏览器指定回退方案,否则,图案会默认放在左上角. < ...

  6. HDU 3785 寻找大富翁

    寻找大富翁 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  7. Python - Python2与Python3合理共存Windows平台

    Install Python2 and Python3 Python 2.7.13 - Windows x86-64 MSI installer Python 3.6.0 - Windows x86- ...

  8. c#入门系列——基础篇

    c#与VB的区别 刚接触c#发现c#与vb还是有所不同的--它可以在控制台显示.它比vb多出来了一些东西.代码规范上跟VB也稍有不同.....暂时就发现这么多,正在努力发现中. c#的代码结构     ...

  9. matlab 利用persistent关键字 存储持久变量

    数学知识:标准差体现随机变量取值与其期望值的偏差.标准差的值较大,则表明该随机变量的取值与其期望值的偏差较大反之,则表明此偏差较小.函数功能:函数必须能够接受一次输入值并记录对应的已输入数N.sum( ...

  10. IE中使用ajaxSubmit上传文件弹出下载提示框

    使用jQuery的ajaxSubmit 上传文件时,在IE中会弹出下载提示框: 解决方法:让action返回String类型,而不是ActionView,