1、前言
javascript
当使用CoffeeScript、ClojureScript编写前端脚本时,当使用Less、Sacc编写样式规则时,是否以为调试时没法准确找到源码位置呢?当使用jquery.min.js等经压缩后的工具库时,是否以为连调试的门都不不知道在哪呢?css
针对上述问题,google为咱们提供了Source Maps这一解决方案,如下内容为对Source Maps的学习记录,以便往后查阅。html
因为篇幅较长,特设目录一坨!前端
2、示例java
3、Source Maps方案详解jquery
1. 方案结构apache
2. 支持的浏览器和启动方式json
3. 生成器api
首先咱们使用ClojureScript写一段递归函数becomeGeek
(ns sample) (defn becomeGeek [progress] (.log js/console progress) (if (> 100 progress) (becomeGeek (+ 1 progress))))
预编译后获得以下js
sample.becomeGeek = (function becomeGeek(process){ console.log(process); if(((100) > process)){ return becomeGeek.call(null,((1) + process)); } else { return null; } });
当须要调试时咱们的处境就是看着JS代码修改ClojureScript代码,对于这个becomeGeek函数来讲没多大困难,但对于整个工程来讲难度不亚于看着二进制中间码来修改Java代码哦。下面咱们经过lein+cljsbuild插件来生成source maps从而解决上述问题!
project.clj配置信息
(defproject sample "0.1.0-SNAPSHOT" :dependencies [[org.clojure/clojure "1.6.0"] [org.clojure/clojurescript "0.0-2411" :exclusions [org.apache.ant/ant]] [compojure "1.1.6"]] :plugins [[lein-cljsbuild "1.0.4"]] :cljsbuild { :builds [{:id "main" :source-paths ["src-cljs"] :compiler {:output-to "js/main.js" :output-dir "out" :optimizations :none :source-map true}}]})
执行lein命令
$ lein cljsbulid once
而后咱们开启Chrome的devTools中js和css的source maps功能便可像在VS上调试C#同样爽快了。
在sample.cljs文件中设置断点,而后调用sample.becomeGeek调试便可!
Chrome的devTools:
FF的devTools:
我想你们如今已经感觉到Source Maps的威力了,有了它咱们就能够安心的使用JS的超集语言(ClojureScript、CoffeeScript和TypeScript等),也可安心调试jquery.min.js等通过压缩混淆的库代码了。
Source Maps不只仅是一个.map后缀的文件,而是由浏览器、.map文件生成器和.map文件组成的一套技术方案。
.map文件,实际上是一个关系映射文件,用于存放源码和编译后代码的文件、行号、列号和变量名的映射关系;
.map文件生成器,每种预处理器(Lessc、Closure、cljsc等)均可经过可选项设置如何生成.map文件;
浏览器,Chrome和FF均提供Source Maps支持(IE11依然不支持),浏览器实质上提供的是.map文件解析引擎,根据.map文件内容加载源文件和在调试模式中关联源码和编译后代码。
另外编译后代码最后一行会追加一行指向.map文件语句,指向的方式有http uri scheme 和 data uri scheme两种。
http uri scheme,格式为 //# sourceMappingURL=sample.js.map?rel=1420853090118
data uri scheme,就是经过对.map文件进行base64编码,而后编译后代码最后一行以data uri scheme的形式引入.map文件内容,格式为 //# sourceMappingURL=data:application/json;base64,Asdi.......
Chrome,devTools的Settings中开启JS和CSS的Source Maps功能。
FF,默认已经开启JS和CSS的Source Maps功能。
下面将介绍Lessc、GC(Google Closure Compiler)、UglifyJS、ClojureScript和CoffeeScript
Less的生成器为lessc,经过可选项 --source-map 开启生成.map文件的功能,并经过如 --source-map-rootpath 等可选项配置.map文件的相关信息。具体请查看《前端构建:Less入了个门》
GC,做为JS的编译器,不但提供去除空白、注释等功能,还会对代码进行语法分析并优化代码(函数内联、变量常量化、局部变量和属性名替换等)
a = new Object => a = {} a = new Array => a = [] if (a) b() => a && b() return 2 * 3; => return 6;
GC提供三种调用方式,分别为网页版、网络API版和独立应用程序。因为GC使用Java编写,所以咱们须要安装JRE。(若不想安装JRE那么可参考@赵劼经过IKVM.NET来将clojure-compiler.jar转码为.Net版)而后经过下面的命令生成.map文件:
$ java -jar compiler.jar --js sample.js --create_source_map ./sample-map --js_output_file sample.min.js
UglifyJS,因为jQuery改用UglifyJS做为其预编译工具令其声名远播,经过下面的命令生成.map文件:
$ uglifyjs sample.js -o sample.min.js --source-map sample.min.map
ClojureScript,咱们能够经过第二节的方式生成.map文件。
CoffeeScript,经过下面的命令生成.map文件:
coffee -c sample.min.js sample.js -m
到这里你们已经能够驾轻就熟地使用Source Maps了,接下来的内容是为想再深刻理解.map文件内容和Source Maps实现原理的朋友准备的。内容主要来自@阮一峰的《Javascript Source Map 详解》
以第二节生成的.map文件为例
{"version":3, "file":"/C:/lein/myapp/out/sample.js", "sources":["sample.cljs?rel=1420853090124"], "sourceRoot":"","mappings": ";AAAA;;AAEA,oBAAA,pBAAMA,yCAAYC;AAAlB,AACC,AAAMC,YAAWD;;AACjB,GAAI,CAAA,QAAOA;AACV,OAACE,qBAAW,CAAA,MAAKF;;AADlB", "names":["sample/becomeGeek", "process", "js/console", "becomeGeek"]}
{Number} version,Source map的版本,目前为3;
{String} file ,编译后的文件路径;
{Array.<String>} sources ,源码文件路径数组;
{String} sourceRoot ,源码文件的所在目录;
{Array.<String>} names ,源码中的全部变量名和属性名;
{String} mappings ,记录源码与编译后代码的位置信息。
首先mapping属性值分为三层含义
①以分号(;)标识编译后代码的每一行,便是分号间隔的内容表明编译后代码的一行;
②以逗号(,)标识编译后代码该行中的每个映射位置,便是逗号间隔的内容表明一个映射位置;
③以5组VLQ编码字段标识源码和编译后代码的具体映射信息。从左至右每组表示以下:
第1组,表示对应编译后代码的第几列;
第2组,表示源码所属文件在sources数组中的索引值;
第3组,表示对应源码的第几行;
第4组,表示对应源码的第几列;
第5组,表示在names数组中的索引值,若没有则可省略。
注意:每组VLQ编码字段有0~N个VLQ编码字符组成,如qCAAUH。
4.3. VLQ编码
VLQ编码最先用于MIDI文件,后来被多种格式采用。它的特色就是能够很是精简地表示很大的数值。
VLQ编码是变长的。若是(整)数值在-15到+15之间(含两个端点),用一个字符表示;超出这个范围,就须要用多个字符表示。而且规定每6bit标识一个字符。
Continuation | Sign | | V V 101011
第一位(Continuation位)表示当前6个bit是否为当前编码段的最后一节,1表示不是,0表示是。
最后一位(Sign位),当该节为当前编码段的第一节时,表示符号1为负号,0为正号;若不是第一节则表示数值位。
下面对16进行VLQ编码,
1. 将16转换为二进制10000;
2. 在最右边补充符号位(Sign位)获得100000;
3. 从最右边开始以5bit为一组对其进行分段,分段后不足5bit的在前面补0,获得0000一、00000;
4. 倒序获得00000、00001;
5. 为每一段添加连续位(Continuation位)获得100000、000001;
6. 对每段进行Base64编码,获得gB。(下图为Base64编码字符集)
经过Chrome和FF下devTools的network面板咱们能够看到浏览器加载了.map文件和源代码文件,如今问题来了,那么在生产环境当中用户访问网页时岂不会多加载两个开发环境使用的文件吗?
其实浏览器默认状况下(不打开devTools时)是不会加载.map文件和源代码文件的,因此你们能够放心了。假如你仍是怕用户误操做打开了devTools,那么就在打包发布时不生成.map文件就行了!
以前尝试过CoffeeScript,但因为编码速度虽然提升很多,但调试效率却下降更多(without source maps之痛),致使最终回归JS的怀抱了。如今咱们终于能够安心使用CoffeeScript咯!
尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/4208566.html ^_^肥仔John
6、参考