在我的博客Adebuggingissuecauseofsourcecodemapping中,介绍了我在做SAPC4C开发时困扰我很久的一个问题,最后总结是不是这个问题由于JavaScript的源代码映射机制在Chrome开发者工具中起作用,所以它实际上是一种按设计工作的行为。不过当时由于时间关系,并没有去研究JavaScript源码图的更多细节。在本文中我使用一个简单的UI5应用来研究该机制。这个应用的UI只有一个Button,点击后弹出一个MessageToast。下面是我的XML视图和控制器实现。在Chrome开发者工具中打开源码映射开关:然后在浏览器中访问UI5应用,我们可以在Chrome开发者工具中看到这些UI5库文件的调试版本(.dbg.js)。但是在Chrome开发者工具的网络选项卡中,我们无法观察到这些调试版本文件的加载。那么问题来了:这些.dbg.js文件是从哪里来的?关闭Chrome开发者工具的源码映射功能后,我们在Chrome开发者工具中就再也观察不到这些.dbg.js文件了。对比下图和打开源码图时的截图:如何在本地找到sap-ui-core.js.map文件点击sap-ui-core.js,在最后一行1875可以看到内容这行://#sourceMappingURL=sap-ui-core.js.map这个文件的后缀.map给了我们一个提示:它的作用是维护位置映射关系,而sap-ui-core.js(压缩文件)中的代码位置映射到压缩前的代码位置(压缩前的文件名、代码行数、代码列数、压缩前涉及的JavaScript变量的名称)。但是,同样地,我无法观察到这个.map文件被加载到开发人员工具的网络选项卡中。在Chrome中输入url:“chrome://net-internals/#events”,结果显示确实有访问sap-ui-core.js.map的url请求,只是因为本地磁盘缓存可以响应request,所以没有生成真实的网络请求:在chrome中输入“chrome://cache”,可以看到chrome所有的本地缓存。从这里,我成功找到了文件sap-ui-core.js.map的本地缓存。单击超链接可查看此缓存的标头信息。但是缓存的具体文件内容显示格式为HEX,无法直接分析。因此,我使用GoogleChromeWeb浏览器的缓存查看器工具将缓存导出为本地文件。sap-ui-core.js.map文件内容概览这篇博文JavaScriptSourceMaps简介介绍了JavaScript源代码映射的基础知识。sap-ui-core.js.map文件的内容:version:3.map文件的各个组成部分的作用和含义定义在一个名为SourceMapRevisionProposal的协议文档中,在我的例子中是sap-ui-core.js.map中使用了该协议的版本3。sources:这是一个数组,其中包含用于生成压缩js文件的所有原始文件的名称。names:这是一个数组,包含出现在原始js文件中的JavaScript变量和属性名称。下面举例将原始文件之一的Device-dbg.js中的变量名,以及它们在sap-ui-core.js.map文件中的names数组中的对应记录,方便大家参考。mappings:.map文件中最重要的部分,定义了原文件中的位置与生成的压缩版文件中的位置的对应关系。通信记录的粒度以压缩后文件的每一行为准,以分号分隔。这样做的好处是不需要分配额外的位来维护归档位置的行号信息。回到我的例子,压缩文件sap-ui-core.js一共有1874行,所以sap-ui-core.js.map一共有1874个分号,每个分号都是一个很长的字符串,由一系列逗号分隔,这些以逗号分隔的字符串段称为段。每个段都维护一个位置的映射关系。如何生成.map文件有很多用于生成.map文件的开源组件,GoogleClosure编译器就是其中之一。假设我想在我的测试应用程序中根据控制器实现文件生成一个压缩版本的文件App.controller.js:从谷歌网站下载compile.jar,然后生成一个名为script-min.js和脚本的压缩文件-min.js.map:java-jarcompile.jar--jsApp.controller.js--create_source_map./script-min.js.map--source_map_format=V3--js_output_filescript-min.js生成压缩文件脚本-min.js只有一行内容:generatedscript-min.js.map内容:这些段可以使用vlq.js解码:浏览器打开html并产生以下输出:每个段由4或5个字符组成.各位对应含义:第一位表示该位置在转换后的压缩文件的哪一列。第二位,sources数组中的索引,表示该位置来自哪个原始文件。第三位表示该位置属于原文件的哪一行。第四位表示该位置在原文件中属于哪一列。第五位,名称数组中的索引,表示该位置属于源文件中的哪个变量。有关VLQ编码的更多详细信息,您可以阅读这篇博客SourceMapsunderthehood–VLQ,Base64andYoda
