- 浏览: 43152 次
- 性别:
- 来自: 深圳
最新评论
http://www.cnblogs.com/xuld/p/5882677.html
一、什么是源映射
为了提高性能,很多站点都会先压缩 JavaScript 代码然后上线,
但如果代码运行时出现错误,浏览器只会显示在已压缩的代码中的位置,很难确定真正的源码错误位置。
这时源映射就登场了。
源映射(Source Map)是一种数据格式,它存储了源代码和生成代码之间的位置映射关系。
源映射一般使用 .map 扩展名,源映射本质是一个 JSON 文本文档,其 MIME 类型也一般设为 application/json。
二、如何使用源映射
在 JavaScript 代码中添加注释:
//# sourceMappingURL=file.js.map
浏览器(最新版 Chrome、Firefox 和 Edge 均支持)就会加载 file.js.map 并自动计算代码的实际位置。
在 Chrome 开发面板(按F12打开)的设置(按F1打开)中,可以通过勾选 "Enable Source Maps" 选项来设置是否需要加载源映射。
源映射本身并不会影响代码的执行,只会在定位错误位置时被使用。
最早浏览器是通过 "@ sourceMappingURL" 标记地址的,但这引发了一些引擎和工具的问题(和 IE 的 @cc_on 冲突),所以现在改成了 "# sourceMappingURL"。
NodeJS 中的源映射
NodeJS 在显示错误堆栈时,并不会加载源映射,可以借助 source-map-support 这个包实现。
$ npm install source-map-support
然后在代码顶部加上:
require('source-map-support/register');
这时所有堆栈位置就会被更新成真正的源码位置。
VSCode 中的源映射
VSCode 支持在调试时使用源映射,在 .vscode/launch.json 中添加:
复制代码
{
"configurations": [
{
"sourceMaps": true,
"outDir": "${workspaceRoot}/build"
}
]
}
复制代码
注意必须设置 outDir,否则可能出现无法添加断点的问题。
三、如何生成源映射
现在很多生成工具都支持生成源映射,如 Uglify, Grunt, Gulp,可以参考生成工具的文档。
四、源映射格式详解
源映射本质是一个 JSON,格式如:
复制代码
{
version: 3,
file: 'min.js',
names: ['bar', 'baz', 'n'],
sourceRoot: 'http://example.com/www/js/',
sources: ['one.js', 'two.js'],
sourcesContent: ['', ''],
mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
}
复制代码
主要包括以下字段:
version: Source Map(源映射)的版本号,目前统一使用版本 3。
file: (可选)生成文件的路径(相对于 Source Map(源映射) 本身路径)。
names: (可选)所有名称,如变量名、函数名,下文详细介绍。
sourceRoot: (可选)所有源文件的根路径(相对于 Source Map(源映射) 本身路径)
sources: 所有源文件的路径(相对于 sourceRoot)
sourcesContent: (可选)所有源文件的内容。
mappings: 所有映射点,下文详细介绍。
其中,所有相对路径的计算方式和网页中的相对地址相同。
所有地址可以是 http:// 开头的网址或者是本地文件地址。
sources
sources 是一个数组,这意味着一个文件可以从多个文件生成过来。
很多读者会觉得这里出现的路径太多,帮大家捋一捋:
假如源文件是 xld.js ,通过压缩生成了 xld.min.js 和 xld.min.js.map ,那么:
在 xld.min.js 中需要通过 // #sourceMappingURL=xld.min.js.map 指定它的源映射。
在 xld.min.js.map 中需要通过 file: xld.min.js 指定它生效的文件。file 并不是必须的字段,该字段只用于检验。
在 xld.min.js.map 中需要通过 sources: ["xld.js"] 指定真正的源文件地址。
sourceRoot
如果 sources 有很多且有相同的前缀,则可以统一提取到 sourceRoot 中。所以以下是等价的:
{
sources: ["a/foo.js", "a/bar.js"],
}
{
sourceRoot : "a",
sources: ["foo.js", "bar.js"],
}
mappings
mappings 是记录映射关系的核心。
从表面看,mappings 是一个字符串,里面由很多看似乱码的字符组成。
其实 mappings 是一个数组通过一定的方式编码得到的,这个数组包含了生成的文件中每行的映射点列表:
mappings = [
第 1 行的映射点列表,
第 2 行的映射点列表,
...
]
每行的映射点列表又是一个数组,包含了该行中所有列的映射点。
mappings = [
[ 第 1 行第 1 个映射点, 第 1 行第 2 个映射点, ... ] // 第 1 行的映射点列表
[ 第 2 行第 1 个映射点, 第 2 行第 2 个映射点, ... ] // 第 2 行的映射点列表
...
]
每个映射点又是一个数组,数组中包含了 5 个数字:
[ 生成文件的列, 源文件索引, 源文件行号, 源文件列号, 名称索引 ]
其中,名称索引可省略。源文件索引, 源文件行号, 源文件列号也可同时省略,
这表示映射点的数组长度可能是 1、4 或 5。
源映射所有行列号都是从 0 开始计数的,本文中所使用的行列号也都是从 0 开始计数的。
举个例子,比如现在有一个源映射如下:
复制代码
1 {
2 version: 3,
3 file: 'min.js',
4 names: ['bar', 'baz', 'n'],
5 sourceRoot: 'http://example.com/www/js/',
6 sources: ['one.js', 'two.js'],
7 sourcesContent: ['', ''],
8 mappings: [
9 [],
10 [],
11 [
12 [1, 0, 2, 5, 1],
13 [4, 0, 3, 6, 0] // #13 行
14 ]
15 ]
16 }
复制代码
以 #13 行数据为例:#13 行出现在 mappings[2] 里面,因此它表示生成的文件第 2 行的信息。
#13 行包含了 5 个数字,分别表示生成文件的列 = 4, 源文件索引 = 0, 源文件行号 = 3, 源文件列号 = 6, 名称索引 = 0。
最终得到:生成的文件(即 min.js)中,行 2 列 4 的位置是从第 0 个源码(即 http://example.com/www/js/one.js)中行 3 列 6 的位置生成的,源码中相关的名称是 0(即 bar)。
通过多个映射点,可以一一定义生成的文件中每个位置对应的实际源码位置。
注意即使指定了某一行列的源码位置,也无法推断相邻行列的源码的位置,必须一一添加映射。
名称索引可以用于快速定位变量和函数压缩前的名字。
mappings 编码
为了节约存储空间,mappings 会被编码成一个字符串。
第一步:计算相对值
将映射点中每个数字替换成当前映射点和上一个映射点相应位置的差,如:
复制代码
mappings: [
[
[1, 0, 2, 5, 1],
[2, 0, 3, 6, 0]
],
[
[5, 0, 2, 3, 0]
]
]
复制代码
其中第一个映射点不变,以后每个映射点上每个数字都减去上一个映射点(允许跨行)对应位置的数字(如果映射点元素个数不足 5,则省略部分按 0 处理),最后得到:
复制代码
mappings: [
[
[1, 0, 2, 5, 1], // 不变
[1, 0, 1, 1, -1] // 1 = 2 - 1, 0 = 0 - 0, 1 = 3 - 2, 1 = 6 - 5, 1 = 0 - 1
],
[
[3, 0, -1, -3, 0] // 3 = 5 - 2, 0 = 0 - 0, -1 = 2 - 3, -3 = 3 - 6, 0 = 0 - 0
]
]
复制代码
第二步:合并数字
将 mappings 中出现的所有数字写成一行,不同映射点使用,(逗号)隔开,不同的行使用;(分号)隔开。
1 0 2 5 1 , 1 0 1 1 1 ; 3, 0 , -1, -3, 0
第三步:编码数字
对于每个数字,都使用 VLQ 编码 将其转为字母,具体转换方式为:
1. 如果数字是负数,则取其相反数。
2. 将数字转为等效的二进制。并在末尾补符号位,如果数字是负数则补 1 否则补 0。
3. 从右往左分割二进制,一次取 5 位,不足的补 0。
4. 将分好的二进制进行倒序。
5. 每段二进制前面补 1,最后一段二进制补 0。这样每段二进制就是 6 位,其值范围是 0 到 64(含0,不含64)。
6. 根据 Base64 编码表将每段二进制转为字母:
以 170 为例,
1)转为二进制即:10101010
2)170 是正数,右边补 0:101010100
3)从右往左分割二进制:10100, 1010。
4)不足 5 位的补 0:01010, 10100
5)倒序:10100, 01010
6)除最后一个前面补 0,其它每段前面补 1:110100, 001010
7)转为十进制:52, 10。
8)查表得到:0K
任意一个整数都能通过 VLQ 编码得到一串字母和数字表示的文本。
VLQ 编码最早用于MIDI文件,它可以非常精简地表示很大的数值。
第四步:合并结果
将第二步中的每个数字进行 VLQ 编码再拼接就是最终的结果。
CAEKC,CACCC;GADHA
五、源映射相关的工具和框架
为更好理解源映射,可以使用 源映射可视化 工具。
为了处理源映射,可以使用官方的 source-map 库。
同时推荐更好用的库:source-map-builder,它相比官方的库性能更高、具有更智能的推导功能。
六、参考链接
Source Map Revision 3 Proposal
http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/
http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html
发表评论
-
vue声明周期
2019-02-25 21:51 0vue -
Vue生命周期 VS React生命周期
2019-01-29 11:12 0Vue生命周: beforeCreate: c ... -
vue双向绑定原理解析
2018-12-23 10:59 0通过简单的实例解析vue双向绑定的原理。 let vm= ... -
常见轮播图
2018-09-26 17:16 616端开发中基本上每个项目都会用到轮播图,今天我们就对常见轮播 ... -
前后端连载启动
2018-09-13 16:46 0安装:npm i concurrently -D 配 ... -
微信小程序-介绍
2018-08-26 19:25 01,什么是微信小程序? 2,微信小程序用途? 3,微信 ... -
vue-vuex
2018-08-15 12:02 0vuex是什么? 官方解释: vuex是一个专为vue. ... -
3大前端主流框架对比
2018-07-21 22:07 0vue vs react vs angular angul ... -
webpack配置文件
2018-03-14 17:36 0webpack配置文件 由于在实际项目中的需求要复杂的多 ... -
gulp
2017-08-10 17:33 52http://web.jobbole.com/86025/ -
BootStrap学习笔记,优缺点总结
2017-05-22 10:24 359本篇约定Bootstrap简写为B ... -
react
2017-02-02 15:52 54react是什么? 颠覆式前端ui开发框架。 react特点? ... -
简单功能强大的jQuery图片剪裁插件Image Cropper
2016-10-29 15:55 75相信很多朋友都在大型的网站,如新浪微博、QQ微博上看到过头像裁 ... -
grunt学习
2016-10-14 14:57 47jshint: js代码校验工具 常用参数详解: bitwis ... -
experss安装说明
2016-06-27 23:11 501、安装express及相关组建-----cmd下运行:npm ... -
NodeJS、NPM安装
2016-06-13 12:03 64NodeJS、NPM安装配置步骤( ...
相关推荐
源地图合并source-map-merger是CommonJS模块,它允许将多个Source-Map组合为一个。 考虑一下在JavaScript构建过程中执行多个处理步骤的场景: 将您的代码转换为JavaScript(CoffeeScript,TypeScript) 依赖性解析和...
source-map-loader, 从模块中提取sourceMappingURL注释并将它的提供给 web service 加载器从现有源文件( 从他们的sourceMappingURL ) 中提取源映射。安装npm i -D source-map-loader用法文档:使用加载程序工具 web ...
[dependencies] sourcemap =“ *”如果要使用git版本:[dependencies.sourcemap] git =“ https://github.com/getsentry/ rust-sourcemap.git”的基本操作该板条箱可以从JSON文件加载JavaScript源地图。 它使用serde...
ATL接口映射宏详解 ATL接口映射宏详解 ATL接口映射宏详解
源映射完全是通用的(不特定于任何一种语言),因此您可以在同一节点进程中使用具有多种可编译为JS语言的源映射。 安装及使用 节点支持 $ npm install source-map-support 可以使用诸如库来生成。 获得有效的源...
Elastic APM Sourcemap操作保存源地图以用于Kibana APM。 要求源映射的名称与其附加了.map的捆绑包的名称相同。输入项apm_node 必需的Elastic APM端点。service_version 必需RUM代理中使用的服务版本。service_name ...
前端开源库-gulp-concat-sourcemapGulp Concat源映射,连接文件并生成源映射文件
multi-stage-sourcemap映射可以将C.js映射到A.js 一种简单但有损的方法是出于调试目的而忽略过程中的中间步骤,或者忽略翻译中的源位置信息(将中间翻译视为“原始源”),或者通过源位置信息进行传递(隐藏的中间...
尝试使错误堆栈与浏览器中的源映射一起使用,但仅支持Chrome。 该代码主要来自 ,但简化为仅与浏览器一起使用,并已固定为支持所有源映射模式 基本上,这是v8 一种hack 适用于babel和webpack :grinning_face_with...
java中Map映射机制 java中Map映射机制 java中Map映射机制
Hibernate_关联关系映射配置详解,希望能帮助广大java爱好者
哈希映射 hash map hash_map基于hash table(哈希表)。哈希表最大的优点,就是把数据的存储和查找消耗的时间大大降低,几乎可以看成是常数时间;而代价仅仅是消耗比较多的内存。然而在当前可利用内存越来越多的情况...
badjs-sourcemap 接收由 发送过来的文件 配置说明 { "port": 80, // 监听的端口 "output": "./maps" // 接收的文件解压(unzip)的路径, 需要保证有写权限 } tips:功能上来说,支持简单文件备份,并不局限于 ...
源映射 介绍 考虑到发布环境不附加sourcemap文件,收集到的错误总是被改过的,需要一个解析工具进行解析,映射到源文件。 本工具基于官方映射工具以及工具 专门针对前端[removed] 到的JSON.stringfy(errorObj.stack...
Hibernate的映射配置文件详解,非常实用
通过源映射分析和调试JavaScript(或Sass或LESS)代码膨胀。 源映射浏览器确定您的缩小代码中每个字节来自哪个文件。 它显示了可视化,以帮助您调试所有代码的来源。 此(3:25),以获取该工具的演示。 安装: ...
Hibernate映射配置详解
创建 SourceMap 实例您可以从另一个源映射或通过一次创建一个映射来创建源映射。从现有源映射创建要从现有源映射创建源映射,您必须首先通过从您正在运行的任何转译器请求对象版本或使用JSON.parse或任何其他 JSON ...
什么是端口映射 这里说的端口映射是路由器上的端口映射。一般情况下,网络中路由器都有防火墙功能,互联网用户只能访问到你的路由器WAN口(接ADSL线口或是固定的外网IP地址),而访问不了局域内部服务器或工作站。要想...
源地图查找消费源地图的工具。 因为我们定期在已编译和精简的React代码中以行号和列号的形式获取错误报告,所以构建该漏洞。 由于webpack输出地图文件,因此我构建了此命令行工具,用于获取地图文件的路径和所报告的...