Source Map入门教程

部署前端之前,开发者通常会对代码进行打包压缩,这样可以减少代码大小,从而有效提高访问速度。然而,压缩代码的报错信息是很难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将非常方便。

参考链接

时间: 2024-10-01 18:46:24

Source Map入门教程的相关文章

Android基础入门教程——4.2.3 Service精通

Android基础入门教程--4.2.3 Service精通 标签(空格分隔): Android基础入门教程 本节引言: 本节,我们继续来研究Service(服务)组件,本节将会学习下Android中的AIDL跨进程通信的一些 概念,并不深入到源码层次,暂时知道是什么,会用即可!开始本节内容~ 本节对应官方文档:Binder 1.Binder机制初涉 1)IBinder和Binder是什么鬼? 我们来看看官方文档怎么说: 中文翻译: IBinder是远程对象的基本接口,是饿了高性能而设计的轻量级

【OpenCV入门教程之十八】OpenCV仿射变换 &amp; SURF特征点描述合辑

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/33320997 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 知乎:http://www.zhihu.com/people/mao-xing-yun 邮箱: [email protected] 写作当前博文时配套使用的OpenCV版本: 2.4.9 本篇文章中,我们一起探讨了OpenCV中

【译】Thrust快速入门教程(四) —— Fancy Iterators

高级迭代器可以实现多种有价值功能.本节将展示如何利用高级迭代器和标准Thrust算法处理一个更广泛的类问题. 对于那些熟悉的Boost C ++库的开发者,他们会发现Thrust的高级迭代器与Boost迭代器库非常相似. constant_iterator 常量迭代器最明显的特点,是每次解引用时,都会返回一个相同的值.下面的例子我们将一个常量迭代器的初始值设置为10. 1 #include <thrust/iterator/constant_iterator.h> 2 ... 3 // cre

OpenLayers 3 入门教程

OpenLayers 3 入门教程摘要OpenLayers 3对OpenLayers网络地图库进行了根本的重新设计.版本2虽然被广泛使用,但从JavaScript开发的早期发展阶段开始,已日益现实出它的落后. OL3已运用现代的设计模式从底层重写. 最初的版本旨在支持第2版提供的功能,提供大量商业或免费的瓦片资源以及最流行的开源矢量数据格式.与版本2一样,数据可以被任意投影.最初的版本还增加了一些额外的功能,如能够方便地旋转地图以及显示地图动画. OpenLayers 3同时设计了一些主要的新功

[EA]入门教程

一.简介 生命周期软件设计方案--Enterprise Architect是以目标为导向的软件系统.它覆盖了系统开发的整个周期,除了开发类模型之外,还包括事务进程分析,使用案例需求,动态模型,组件和布局,系统管理,非功能需求,用户界面设计,测试和维护等.为整个团队提供高级的UML 2.0建模工具. EA为用户提供一个高性能.直观的工作界面,联合UML 2.0最新规范,为桌面电脑工作人员.开发和应用团队打造先进的软件建模方案.该产品不仅特性丰富,而且性价比极高,可以用来配备您的整个工作团队,包括分

Flux 架构入门教程

过去一年中,前端技术大发展,最耀眼的明星就是React. React 本身只涉及UI层,如果搭建大型应用,必须搭配一个前端框架.也就是说,你至少要学两样东西,才能基本满足需要:React + 前端框架. Facebook官方使用的是 Flux 框架.本文就介绍如何在 React 的基础上,使用 Flux 组织代码和安排内部逻辑,使得你的应用更易于开发和维护. 阅读本文之前,我假设你已经掌握了 React .如果还没有,可以先看我写的<React入门教程>.与以前一样,本文的目标是使用最简单的语

Maven入门教程

Maven入门教程一.maven简介 Maven是一个项目管理工具 它包含: 一个项目对象模型 (Project Object Model) 一组标准集合 一个项目生命周期(Project Lifecycle) 一个依赖管理系统(Dependency Management System) 用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑 项目结构: 源代码放在src/main/java 源代码的资源文件放在src/main/resources 测试代码放在sr

threejs构建web三维视图入门教程

本文是一篇简单的webGL+threejs构建web三维视图的入门教程,你可以了解到利用threejs创建简单的三维图形,并且控制图形运动.若有不足,欢迎指出. 一.创建场景我们所见的视图由两个部分共同创建,scene和camera.首先定义一个场景:var scene = new THREE.Scene();然后定义一个相机:var camera = new THREE.PerspectiveCamera( 90, width/height, 0.1, 1000 );等等,定义相机需要视窗的长

iBatis简单入门教程

iBatis 简介: iBatis 是apache 的一个开源项目,一个O/R Mapping 解决方案,iBatis 最大的特点就是小巧,上手很快.如果不需要太多复杂的功能,iBatis 是能够满足你的要求又足够灵活的最简单的解决方案,现在的iBatis 已经改名为Mybatis 了. 官网为:http://www.mybatis.org/ 搭建iBatis 开发环境: 1 .导入相关的jar 包,ibatis-2.3.0.677.jar .mysql-connector-java-5.1.6