使用Ant编译Web应用

前端项目可能碰到两个很大的问题:代码开放,用户可以直接读代码;代码下载需要占用带宽。这两个问题用ant编译可以在很大程度上得到解决。

开发只是万里长征走完前半截,测试部署也是很重要的环节。

尤其是,前端面临着两个很大的问题:

  1. 前端代码是开放的,用户随时可以直接读代码
  2. 代码下载到用户电脑上运行,需要占用带宽

所以如果我们可以先压缩、混淆代码,再部署给用户使用,就可以大大改善这种情况。这个时候,ant是不二的选择(因为我只会ant……)。

关于Ant

下载:http://ant.apache.org/bindownload.cgi

手册:http://ant.apache.org/manual/index.html

基础

ant需要java环境,配好后就可以使用了。默认情况下,ant会读取同目录的build.xml作为编译脚本。

build.xml也遵守一般的XML规则,比如只能有一个根节点,可以使用<![CDATA[ …. ]]>来包裹文本数据等。具体的写法我就不多说了,随便去github上找个工程做参考,配合手册一看就明白。接下来说说我编译的思路。

合并JS

项目中会用到大量外部库和框架,比如jQuery、jQueryUI、Mustache、Twitter Bootstrap、Backbone等。这些库一般都压缩过了,不需要再压缩;另外开源的库都有许可协议,理应保留。所以这部分文件简单压缩一下就可以了。这里有三点需要:

  1. 如果文件中包含中文,就必须指定编码,我喜欢UTF-8
  2. 如果文件末尾没有换行符,可能导致出错,所以需要设置fixlastline为true
  3. 如果不给定顺序,会按文件名合并,可能会出错,比如Backbone明显会比Underscore先合并进来,但前者却是依赖后者的,所以就得像我这样按顺序逐一排列
<target name="-concat.js.libs.files">
    <mkdir dir="${dist}/js" />
    <concat destfile="${dist}/js/libs.js" encoding="UTF-8" fixlastline="yes">
      <filelist dir="js/libs/">
        <file name="jquery-1.7.2.min.js" />
        ....
      </filelist>
    </concat>
  </target>

复制HTML和其他素材

HTML包括index.html和一些模版,基本上压缩与否差别不大,所以直接复制就好;图片之类的东西都算素材,也不可能压缩,仍然直接复制。

<target name="-copy.html.files">
  <copy file="index.html" todir="${dist}" />
  <copy todir="${dist}/template/">
    <fileset dir="template/" />
  </copy>
</target>

<target name="-copy.image.files">
  <copy todir="${dist}/img/">
    <fileset dir="img/" />
  </copy>
</target>

编译CSS

现在直接写CSS都弱爆了,大家不是SCSS就是LESS,但是我们发给用户的肯定是最终输出的普通CSS,而且需要事先压缩。我特别喜欢Google,所以我(准备)用GCSS,于是需要用Closure Stylesheet编译CSS。

<target name="-compile.css.files">
  <java jar="${build}/closure-stylesheets.jar" fork="true">
    <arg line="--output-file ${dist}/css/admin.css" />
    <arg line="css/admin.css" />
  </java>
</target>

编译项目JS

目前看来,我直接用Closure Compiler的Simple模式压缩代码是不够的,也没有跟我的代码结构结合起来,不过暂时可以用,等我有空去做自动解决依赖的功能再说吧。关于如何在ant中使用Closure Compiler,可以看这篇文章。不过里面说的不算太详细,比如我不想考虑IE兼容情况,就只能搜到命令行怎么做,最后还是看源码解决的——这就是开源的好处啊~~

<jscomp compilationLevel="simple" warning="default" debug="false" output="${dist}/js/apps.js" encoding="UTF-8">
  <warning group="internetExplorerChecks" level="OFF" />
  <warning group="globalThis" level="OFF" />
  <sources dir="${temp}">
    <file name="apps.js" />
  </sources>
</jscomp>

修改JS引用

最后,既然我把所有库编译成了libs.js,把所有项目JS编译成了apps.js,那么index.html里原有的引用就不行了,我需要把它们改成新的引用。利用Ant提供的replace语法可以实现这个功能。我在index.html里面用“<!– replace start –>”和“<!– replace over –>”作标记,中间是需要替换的。本想替掉全部js,后来发现比如Google Map就不能替换,所以改用这种方式。

<replaceregexp flags="gs" encoding="UTF-8">
  <regexp pattern="\&lt;!-- replace start --\&gt;(.*?)\&lt;!-- replace over --\&gt;" />
  <substitution expression="\&lt;script src='js/libs.js'\&gt;\&lt;/script\&gt;\&lt;script src='js/apps.js'\&gt;\&lt;/script\&gt;" />
  <fileset dir="${dist}/" includes="index.html" />
</replaceregexp>

这里需要注意的是,ant不允许属性值里出现< / >这些符号,所以必须手工转码。我猜<! [CDATA[ …. ]] >也行,不过没试。

总结

我们写的代码是给人看的,所以要尽可能多用注释、多用模式、多换行、用最长的变量名。但最终用户并不关心这个,他们希望跑的越快越好;而个别别有用心的用户呢,我们也不希望他们轻易地读我们的代码。所以,利用Ant编译部署(目前这个版本的build.xml我还没放ftp部分的代码,不过后面会放的)就显得势在必行。

当然,这篇文章里的内容都比较浅显,比如没有增加分支开发的处理,css也只是简单压缩了一下,更没有ftp上传的东西,不过暂时够用了,进阶的内容以后再补充。