ant作为目前中国最受欢迎的开源构建工具,广泛应用于java工程构建。也许你会感到很疑惑,js作为动态语言,并不需要编译过程,为什么需要ant这样的构建工具呢?ant能够帮助前端工程师解决那些问题呢?
来看个经典的应用场景:
在你的页面中需要引用不少的jquery插件,比如plug-1.js、plug-2.js、plug-3.js,yslow关于前端性能优化的第一建议就是页面应该保持尽量少的js和css引用。明显这个场景违背了这个建议,所以我们需要合并这些js插件,合并成plug-combine.js文件,传统的做法是人肉合并,以前本教程作者也是这么干的,但遇到了如下烦恼,plug-1.js是自己写的插件,经常要更新这个文件的代码,每次更新完都要重新人肉更新下plug-combine.js,作为一个懒人,教程作者在想,“有没有一个工具可以帮我自动合并文件呢?当然合并后能够自动调用压缩工具压缩文件就更棒了!”。ant这个神奇的工具就是用来帮前端偷这样的懒的!
ant强大得超乎你的想象,ant提供了一整套的任务列表帮你从重复耗时的构建流程中解脱出来!看到ant这只神奇的蚂蚁能做如此多的事,心动了吗?那么跟着教程作者来学学如何使用ant。
教程作者要强调的一点是ant很简单,只要你有足够的耐心,1天内就可基本掌握其使用方法。
ant是java程序,所以依赖于java运行环境,如果你的机子已经安装JDK,那么请跳过这一步,如果没有请先下载JDK,传送门在此。
(PS:请运行“CMD”,然后键入“javac”,如果出现如下界面说明java环境OK。)
如果出现“’javac’ 不是内部或外部命令,也不是可运行的程序或批处理文件。”,那么请设置下java环境变量。
右击“计算机”,点击“系统设置”,出现如下界面:
新建系统变量,变量名:ANT_HOME,变量值:d:\soft\ant,变量值指向你本机ant的解压目录,请勿直接copy这个变量值。
修改变量:path,在最后添加:%ANT_HOME%\bin;
在”CMD”界面,输入“ant”,如果出现以下内容,说明配置成功!
在d盘新建个ant-demo的目录。
在该目录下新建个build.xml,代码如下:
再准备二个用于合并的js文件,比如a.js和b.js,(随便在二个文件中加些js代码)。
进入cmd界面,敲入ant,留意必须先将目录指向build.xml的根目录。
你将成功输出a_b.js文件,目录结构如下;
build.xml中的代码是什么意思呢?请看下文分解
构建文件是ant执行工程构建的入门文件,构建的所有任务都必须只能写在构建文件内,构建文件必须是符合标准的xml文件,默认的构建文件为build.xml,当你键入“ant”命名执行时,默认执行build.xml。
改变下上一篇的demo,增加点复杂点:创建一个src目录,将合并后的文件放在src目录下,并在合并后的文件内顶部添加一行自定义的合并注释。
新的demo中的build.xml:
在“CMD”界面运行“ant”命令,结果如下:(请确保你的demo中有a.js和b.js)
成功运行后你就会发现生成了一个src目录,目录下有个a_b.js文件,文件的第一行注释是//合并自a.js和b.js,完全符合我们构建要求!
这个demo的代码会比上一篇教程复杂了不少,教程作者来逐个说明下。
property标签为特性标签,你可以理解为编程语言中的属性或者变量,它起到的作用和变量是类似的,赋值后的property,可以在之后的目标任务内方便的引用。
property有二种数据元素:
如何引用property呢?
非常简单,在你需要引用的地方使用${property名}即可,比如demo中的${concat.note}。
property的location属性
property除了value属性外,还有个location属性,起到的作用类似,区别是location属性用来保存路径,location带了路径转换功能,会将路径转成绝对路径,如果你的路径是/,它会自动转换成\,这个属性日后会经常用到。比如下面的代码:
看看输出结果,留意教程作者取的是代码片段,请根据实际情况做下修改。
target标签非常的重要,“目标”标签可以理解为一系列任务标签的容器,是对任务的隐式说明,构建文件允许出现多个target,教程作者的建议是使用更细的target,比如demo中的代码可以修改为:
这里教程作者将一个target拆成了多个target,留意属性depends。
depends用于处理目标依赖,比如这里“build”依赖于“mkdir”和“concat”目标,那么ant会优先执行“mkdir”和“concat”然后才执行“build”。这种依赖机制是ant非常重要的处理模式!体现出ant的灵活性!
任务是ant构建文件的最小构建块,是构建的实施者,demo中的echo、concat都是任务标签,那么ant能完成多少个任务呢,或者说ant有多少构建功能呢?请猛击这里查看,(有个task list)。看了这个任务清单,我想你可以体会到ant究竟有多强大!
教程作者不会对所有的任务标签进行讲解,只讲解前端常用的几个关键任务标签,下一篇教程将详细讲解concat、mkdir、copy等标签用法。
前面二篇教程,主要讲解了ant的基础概念以及二个简单的实际demo,今天这篇文章,教程作者带大家认识下前端常用的几个ant常用任务标签。
concat标签非常常用,我们前端使用ant的一个核心任务,就是合并js/css文件以减少http请求。
属性 |
说明 |
destfile |
合并后的文件的目标路径,包含文件名 |
overwrite |
是否允许覆盖目标文件,默认是允许 |
outputencoding |
输出的目标文件的编码 |
全部属性请看ant的英文文档。
第二篇教程的demo,concat标签内有个header标签,这个标签是用来修改输出的目标文件的头部内容,比如你可以在目标前添加一行合并信息注释等,比如下面的代码:
header有个trimleading用于清理行空白的属性比较关键,其他属性教程作者也不太理解,旧不翻译了,有兴趣的看英文文档。
合并指定路径的文件:
(PS:path子标签的作用在于指定文件路径。)
合并特定的文件集合:
合并src目录下的所有文件,fileset这个标签非常重要,在讲解dataType时会重点说明。
给目标文件增加文字:
利用header标签,demo已经贴出,不再重复贴出。
比较简单,只有一个属性dir,用来指定创建的目录路径,不只是名称哦。
贴个demo:
在${dist}(属性引用)下创建一个名为lib的目录。
属性 |
说明 |
file |
必有属性,用于复制的源文件,除非存在fileset等dataType |
tofile |
将文件复制到该路径 |
todir |
将文件复制到该目录 |
outputencoding |
目标文件的编码 |
将a.js文件复制到src目录下,这里你可以修改文件名哦。
将a.js文件复制到src目录下。
将src的文件(排除css文件)复制到build目录下。excludes=”**/*.css”的含义在讲解fileset会说明。
属性 |
说明 |
file |
删除的目标文件 |
dir |
删除的目标目录 |
verbose |
是否显示每个删除的目标文件名称 |
quiet |
当设置为true,删除的文件或目录出现错误时不抛出任何异常,正常情况下会有删除失败说明 |
删除ant.jar文件和lib目录。
删除根目录下的所有后缀是.bak的文件。
echo在调试ant任务时非常有用,也可以在任务执行后打印一些任务完成提示消息等。
实际上echo也可以把消息打印到指定文件,形成build日志,只需要指定file参数即可。
属性 |
说明 |
message |
想要打印的消息 |
file |
消息打印到指定文件 |
append |
将消息追加到已经存在的文件 |
level |
指定消息的类型,有”error”, “warning”, “info”, “verbose”, “debug” |
来看典型的echo任务代码:
echo打印property属性值,是个非常常用的调试技巧。
上述代码中有个dirname,这个任务是用来做啥的呢?接下去看。
dirname只有二个参数:
属性 |
说明 |
file |
文件路径 |
property |
指定属性名称 |
来看下使用代码:
ant.file这个属性是系统自带的,为当前运行的构建文件路径。
教程作者这里将dirname和property进行比较,二者的输出有明显的区别,dirname只输出目录,property输出完成文件路径,如下图
available任务在防止ant构建时因为文件或目录不存在导致的错误时非常有用。
属性 |
说明 |
property |
属性名 |
value |
属性值,默认为true |
file |
需要验证的文件 |
type |
file的类型,验证目录(type=”dir”) or 验证文件 (type=”file”) |
示例代码
available的value值永远为一个布尔值。
get用于快速将远程文件保存到指定位置,不止支持http:协议,ftp:,jar:也都是可以的。
属性 |
说明 |
src |
源url |
dest |
目标路径 |
verbose |
是否显示下载进度(100 Kb显示一个“.”) |
usetimestamp |
显示最后修改时间 |
username |
‘BASIC’验证页面的用户名 |
password |
‘BASIC’验证页面的密码 |
来看个demo代码:
为了更好说明local用法,教程作者先贴出demo代码:
上述代码会输出如下内容:
在step1目标中我们定义了
local这个任务在sequential(循环)中非常常用,讲到sequential时再演示其用法。
属性 |
说明 |
file |
文件名称 |
datetime |
指定文件修改时间 |
创建一个myfile文件,最后修改时间为当前时间。
创建一个myfile文件,最后修改时间为18/10/2010 2:02 pm。
property(属性)这个标签很常用,当你在build.xml中定义了property,任务可以随意的引用该property,比如以下代码:
当你要引入property,只要使用${property}语法即可。
考虑以下需求:build.xml需要提供给第三方使用,第三方本机的代码路径一般都不一样,如果让第三方自己去修改build.xml的路径配置(假如在你的build.xml中有类似
ant的.properties文件恰恰解决这个需求。
在build.xml同级目录下建立个build.properties(文件名任意);
键入如下示例代码:
打开你的build.xml,插入如下代码:
property的file属性指向build.properties文件,那么ant在执行build.xml前会去找这个文件,build.properties内的属性会覆盖build.xml内的同名属性。
假设你的build.xml有如下property:
你可以试下
这二个属性很容易混淆,不少朋友向教程作者询问,有了value,为什么还需要location呢?二者的作用不是一样的吗?
是的,value和location的功能是接近的,都是property的值,但有些小的区别,如果你的property存储的是路径,那么教程作者推荐使用location属性,location属性会对路径进行转换,永远返回绝对路径形式。来看实际代码:
输出的结果如下:
留意标黄部分的差异,当你使用location属性时,值内所有的“/”都会更换为“\”(即绝对路径的形式),而且还会去掉路径中多余的“/”。所以当你使用location属性存储路径信息时更为安全。
这是ant理论部分的最后一章,也是非常重要的一章,教程作者将介绍ant中常用的几种dataType的用法。
dataType可以理解为复杂数据集合,比如特定规则的文件列表集合。
必须掌握的是:fileset、filelist、path、argument、patternset。
fileset和filelist(下面会讲到),功能上非常相近,都是用于获取一组文件列表,二者的不同之处在于fileset内的文件必须存在,filelist则没这要求;fileset的属性也比filelist更为的丰富,所以功能上更为的强大,一般使用fileset来获取文件。
属性 |
说明 |
dir |
fileset的基目录 |
dir |
fileset的基目录 |
casesensitive |
如果为false,那么匹配文件名时不区分大小写,默认为true |
defaultexcludes |
是否使用默认的排除模式,默认为true。默认的排除模式会把一些版本控制的文件夹或文件排除 |
excludes |
排除指定的文件列表(用逗号隔开) |
excludesfile |
排除指定的文件 |
includes |
需要包含的文件列表(用逗号隔开) |
includesfile |
包含指定的文件 |
concat(合并)这个任务标签,教程作者之前有讲过了,与之前写的demo不同的是,concat内增加了fileset。由于我们的需求是合并uploader目录下的所有js,所以uploader下文件不少,明显不可能单独一个个写path,这时候就需要用到fileset,获取文件列表集合。
fileset会获取${uploader.dir}(该属性引用指向uploader目录)下所有的js,通过includes=”**/*.js”包含所有js。
也许你会对**/*感到疑惑,教程作者下面做个说明。
除了使用属性外,fileset还支持0到n个嵌套patternset元素,比如exclude
、include
等,关于patternset会在下面讲解到,这里先贴出修改后的demo。
这里的demo代码,与上一个demo相比,增加了一个排除文件模式,demo目录下的js文件,显然我们不需要,可以通过exclude
标签予以排除
filelist通常与dependset任务一同使用,dependset任务用于将一个或多个源文件和1个或多个目标文件相比较,如果源文件存在更新或者删除,那么所有目标文件将将被删除。dependset用于确保文件的依赖性。
属性 |
说明 |
dir |
fileset的基目录 |
files |
用逗号隔开的文件列表 |
refid |
对某处定义的一个filelist的引用,这对于希望多次复用一个定义的文件列表,非常有用。 |
filelist的使用率不高,教程作者这里偷个懒,不再制作个独立的demo。
path在java打包编译中常用到,可以以属性(多个路径用冒号或分号隔开)或嵌套元素的方式。
path用于转换路径为当前用户操作系统可兼容的路径。(path dataType并不只有
path
元素,还有classpath
等形式标签)。
属性 |
说明 |
location |
表示一个文件或目录 |
path |
一个文件和路径名列表,以冒号或分号隔开 |
refid |
定义path的一个引用 |
patternset与fileset是紧密结合的,常作为fileset的嵌套元素出现,比如include和exclude标签。
留意代码中的if和unless属性,if=”test”可以理解为如果存在test属性,就读取文件,unless=”demo”可以理解为只有未设置demo属性时才读取文件。
arg标签在apply、exec、java标签内嵌套,用于传递命名行参数。
先贴出日后会说明的demo代码:
上述代码是调用google压缩器压缩js源文件,apply嵌套多个arg标签,比如下面的代码:
执行时会合并成一个命名行,类似–charset gbk –warning_level QUIET –js。
接下来几篇教程作者将开始讲解ant的实战部分的教程。今天介绍是ant如何结合前端必备的yui-compressor或closure-compiler的用法。
yui-compressor已经批处理工具,右键可以压缩文件,已经颇为方便了,为什么还需要ant去调用yui-compressor呢?
思考以下场景:
作为典型的懒人,教程作者渴望有一种工具,运行一次帮我批量压缩文件,然后使用FTP发布到服务器上。ant就是这样的工具。
教程作者已经准备好demo文件(是教程作者正在写的异步文件上传组件),但是务必修改下build.xml文件中的yui-compressor和closure-compiler的路径。
定义属性:源码文件路径,css路径,yuicompressor.jar的路径
任务1:压缩uploader/uploader.css到uploader-min.css
minify-css任务执行yuicompressor.jar,apply标签(dataType),教程作者在上一篇教程中并没有讲到。apply用于执行java程序。留意dest属性,用于指定输出目录,是必须的。
子元素fileset用于提取源文件,这里只需要uploader/uploader.css这个文件。
arg标签上一篇教程教程作者已经讲过了,最后会合并成1行命名。
代码中的mapper标签(dataType)的用途是什么?
mapper定义了一组源文件和一组目标文件的关联方式。共有三个关键属性:
关键看下type属性,当值为glob时,表示基于简单的通配模式(比如*、**)确定文件名。大多数情况glob属性已经够用了。
yuicompressor需要使用mapper来确定批量输出文件规则,教程作者的demo代码很简单,将*.css输出成*-min.css即可。
尝试执行ant minify-css,如果构建顺利的话如下图:
任务2:压缩uploader目录下的js文件为*-min.js
ant执行closure-compiler与yui-compressor基本上一样。closure-compiler的js压缩比yui-compressor强悍,教程作者一般使用closure-compiler压缩js文件,使用yui-compressor压缩css文件。接下来来看下closure-compiler的调用语法。
任务:合并几个js文件,并压缩合并后的文件
合并uploader/base.js、uploader/render.sj、uploader/renderUploader.js为uploader.source.js,并压缩成uploader-min.js。
关于concat任务标签,之前的教程已经讲过乐,教程作者不再累述。重点看下minify-js-closure这个任务。
closure-compiler的调用参数与yui-compressor有一些不同,输出不是使用-o参数,而是使用–js_output_file。
教程作者这里也演示了mapper标签中type=”regexp”的情况,使用正则规则来匹配源文件和目标问题。
(PS:补充个正则知识,(.*)为建立分组捕获,to=”\1-min.js”中的\1,使用该分组。)
上一篇教程教程作者演示了如何使用ant自动压缩文件,今天讲解ant如何ant结合jsdoc构建js文档。
JsDoc Toolkit 是一个将抽离js代码中的注释形成文档的程序,利用ant,你可以自动化打包js文档,需要用到的工具是jsdoc-toolkit-ant-task。调用的过程其实非常简单,整个过程类似ant调用yui-compressor。
下面的代码中,教程作者通过构建kissy-form库(教程作者和其他同事一起写的form组件集,目前还在编码阶段)的文档,演示jsdoc的用法。
假设你已经下载了jsdoc-toolkit-ant-task,且保证你的js代码风格符合jsdoc要求,比如下面的代码:
详尽的jsdoc语法说明,请看jsdoc的wiki。
请根据你本机的情况自行修改目录。
target目标下有二个任务:taskdef定义jsdockit的程序路径,jsdoctoolkit执行真正的构建任务。
接下来教程作者简单说明下其关键属性。
属性 |
说明 |
template |
文档模板 |
outputdir |
文档输出路径 |
inputdir |
js源码目录 |
encoding |
输出文档页面编码,默认是utf-8 |
depth |
程序遍历源码目录的深度,默认是10 |
完成的构建代码如下:
前面8篇ant教程,基本上没有太复杂的地方,在实际项目build中会遇到些复杂的场景。今天这篇教程,教程作者将通过一个真实的项目build过程,来综合演练下ant的用法,同时演示下如何处理ant中的循环任务。
项目名:KF(KISSY-FORM)
用途:kissy的form组件包
源码地址:https://github.com/minghe/kissy-form
KF目前还在开发阶段,完成的组件只有Uploader(异步文件上传),日后会发布更多的form组件,有兴趣的朋友可以关注下。
Uploader场景足够复杂,足以覆盖ant的大部分常用用法,请先下载KF源码到本地,找到Uploader的build.xml文件(form/src/uploader/build.xml)。
build(构建后的打包发布文件)必须和src(源码目录)目录结构保持一致。
任务是不是很多,也许你会觉得教程作者搞得这么复杂很蛋疼,实际上这些任务跟教程作者实际要实现的构建目标有关,不是本文重点,这里不讨论。
接下来来看教程作者是如何实现这些目标的。
由于需要用到第三方类库ant-contrib-1.0b3.jar,请先下载该文件到你的ant/lib目录下。
改名操作不一定要用rename标签,使用move标签也可以间接实现。
这部分的目标也非常简单,使用copy和delete即可实现。
好,进入本文的重点内容,这个任务目标有个难点,就是如何在ant中处理循环?
如上图所示,build和src下的themes目录必须保持一致,而且必须遍历每个子目录合并该目录的js,所以需要用到循环。这时候你也许会想到编程语言中常用的for,ant有for标签吗?很影响ant并不是编程语言,没有直接的for标签,但通过第三方类库可以实现for循环,我们来看代码。
请确保你的本机上的ant下的lib目录下有ant-contrib-1.0b3.jar文件。
给你的project增加ac命名空间:mlns:ac=”antlib:net.sf.antcontrib”。
使用ac:for开启循环,param为参数名,供后面循环时更换文件路径时使用。
定义文件路径。取每个子目录下的index.js。
sequential标签,与for标签配合使用,标志循环开始。
ac:var定义var.dir变量(即子目录路径)可更改,留意ant定义的property是无法更改的。
dirname获取文件对应的子目录路径。
接下来具体执行任务: