BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Dojo Build系统介绍

| 作者 王沛 关注 12 他的粉丝 发布于 2011年9月3日. 估计阅读时间: 15 分钟 | Google、Facebook、Pinterest、阿里、腾讯 等顶尖技术团队的上百个可供参考的架构实例!

1. 简介

Build系统是产品正式发布的最后一道工序,其效率和质量直接决定着最终产品的效率和质量。虽然在传统应用中,Build系统已经相当成熟,但在Web领域,依然是八仙过海,各显神通,甚至不经Build就直接上线的也比比皆是。Web系统的零散性、复杂性,也决定了对其进行Build是一件复杂的事情。但通过Dojo,我们认识到了一款开源的Web应用Build系统:bdBuild,也见识了其强大的功能。它是一个独立的通用Build系统,完全用JavaScript写成,可以运行于NodeJS或者Rhino等JavaScript引擎,理论上可以对任何Web应用进行Build。下面就将介绍Dojo中是如何用bdBuild系统来实现Web应用的Build的。以此为起点,你也可以利用bdBuild实现自己的Web应用Build系统,对非Dojo的应用来进行打包。

2. bdBuild系统简介

bdBuild是一套开源的前端应用Build引擎,完全用JavaScript写成,可运行于Node.js,Rhino等JavaScript引擎。其强大的功能和灵活可扩展的架构使得其能够应用于任何Web应用的打包。Build在传统应用中可以翻译为构建,而在Web中,也许翻译成打包更加适合。一个合格的Web Build系统至少应该能够完成以下几件事情:

  1. 排除开发时文件,比如备份文件,代码中的调试信息,单元测试文件,等等。
  2. 将页面需要的多个资源文件打包成一个文件,并进行压缩,通常是针对JavaScript和CSS文件。这个过程包括了自动处理资源文件之间的依赖关系,能够按顺序进行打包。
  3. 拷贝资源文件到目标位置。

基本上来说,这些工作的最终目的都是为了提高性能,Http协议的特性决定了多次请求取得多个小文件的效率远低于一次请求一个大文件。所以Web Build的首要目标就是合并小文件形成一个大文件。为了实现这些通用功能,bdBuild系统将Build的过程分为以下几个步骤:

  1. 发现资源(discovery)。即找到最终产品所需要的所有资源,不仅包括JavaScript文件,还包括图片,CSS等等。bdBuild实现了默认的资源发现引擎,你也可以通过创建自己的资源发现引擎来告诉系统如何寻找需要的资源。
  2. 转换资源(transform)。即对每个资源进行相应的处理,这个处理是一个有序可扩展的步骤。例如,读取文本,压缩JavaScript代码,就是2 个不同的转换步骤,前面所有转换步骤的结果是作为下一个步骤的输入,这样实现了对资源的多重加工。你可以通过配置文件来加入自己的资源处理步骤。
  3. 控制打包(build control)。这通过一个配置文件,来精确控制每个资源转换的顺序和依赖关系。bdBuild还在其中引入了Gate的概念,将打包过程分为不同的阶段。

虽然当前bdBuild系统仍然处于alpha测试阶段,但是Dojo已经对其进行完善和封装,形成了自己的Build系统,在已经发布的Dojo 1.7 beta版本中,我们已经可以使用它来进行Web应用的打包。

3. Dojo Build系统简介

要使用Dojo的Build系统,首先需要下载源码版的Release包,在util/build下就是build相关的工具:

Dojo 对bdBuild系统进行了相当程度的封装,使得针对Dojo的打包变的更加容易,通过引入层(layer)的概念,可以很方便的指定哪些模块应该被压缩到同一个JavaScript文件。同时,Dojo Build系统还会自动把其它文件拷贝到目标文件夹,每个JavaScript文件或者CSS文件都会同时被压缩。下面的代码说明了layer的作用:

<script type="text/javascript" src="/dojoroot/dojo/dojo.js"></script>
<script type="text/javascript" src="/dojoroot/dijit/dijit.js"></script>
<script type="text/javascript" src="/js /mylayer.js"></script>

这是在页面中引入JavaScript的一段典型代码,其中dojo.js, dijit.js和mylayer.js就是在build系统中配置的3个layer,它们都包含了所有各自需要的代码。通过layer的方式,能够把页面需要的多个JavaScript文件打包成一个,加快了页面的载入速度。layer是在Build的配置文件profile中指定的,如下面的介绍。

Profile的概念

通常一个完整的系统会不只有一个layer,而且对于同一页面,也有可能需要多个layer。所以,Dojo定义了profile这个概念,来描述整个打包的配置和参数。。在dojoroot/util/buildscripts/profiles/下可以看找到系统自带的一些profile文件,它们用于打包标准的dojo.js和dijit.js等等。一个典型的profile文件示例如下:

dependencies = {
    layers: [
    {
        name: "dojo/dojo.js",
        dependencies: [
            "dijit._Widget",
            "dijit._Templated",
            "dojo.fx",
            "dojo.NodeList-fx"
        ]
    }
    ],
    prefixes: [
    [ "dijit", "../dijit" ],
    [ "dojox", "../dojox" ],
    [ "myNamespace", "~/src/myNamespace" ]
    ]
}

文件中定义了一个全局对象dependencies。包含2个必须属性:layers和prefixes。在layers数组中,可以定义多个layer。每个layer的name属性表明了输出的文件,是一个相对于releaseDir(后面介绍如何指定)的相对路径。dependencies数组包含了这个layer需要的模块。Build系统会去递归寻找所有依赖的模块并将它们全部打包进来。

另一个属性是prefixes数组,其中定义的是模块映射关系,它告诉系统到哪里去寻找一个Dojo模块。其作用和应用代码中使用的 dojo.registerModulePath是一样的。Prefixes中的每个元素也是一个数组,包含两个元素,前面是模块前缀,比如 “dijit”,后面一个是相对于util/路径的相对路径,比如“../dijit”。

有了这个profile,我们就可以来进行打包了。在Dojo中,是通过util/build/build.js来完成的。因为Build系统自身的代码都是JavaScript,因此需要一个JavaScript运行环境,现在同时支持的是NodeJS和Rhino。前者通常需要Linux或者 Cygwin环境,后者则需要Java环境的支持。NodeJS比Rhino运行速度快的多,条件允许的话,大家尽可能用NodeJS来进行build。下面的代码演示了如何开始一个build:

使用NodeJS:

node dojoroot/dojo/dojo.js load=build [options]  

使用Java:

java -Xms256m -Xmx256m -jar path/to/util/shrinksafe/js.jar path/to/dojo/dojo.js baseUrl=path/to/dojo load=build [options]

可以看到,build.js文件接受多个参数(options),完整的参数列表可以通过指定—help参数来获取,比如releaseDir指定了要输出 build结果的文件夹。Action指定了要执行的操作序列,例如action=clean,check,release。当然还有一个最关键的参数:profile,它指定了打包的配置文件,从而控制整个打包的过程。例如:

Node dojoroot/dojo/dojo.js load=build profile=/home/dojo/my.profile.js action=check,release

这里的profile可以是如下多种类型:

  • 如果是html文件,则分析其中的dojo.require,从而自动生成一个包含所有模块的profile
  • 如果是标准profile文件,则直接处理
  • 如果是文件夹,则扫描其中的所有以profile.js结尾的文件,分别进行打包。

命令行的完整参数如下面的表格所示:

参数 描述
--build <filename> 指定进行build control的脚本。
--profile <filename> 指定profile文件。
--action 指定要执行哪些操作,比如check, clean, release。
--releaseDir 输出build结果的文件夹。
--version 指定版本号。

Layer的定义

一个profile中可以有多个layer。Layer的配置参数除了上面介绍的name和dependencies之外,还有一个属性非常有用,那就是:layerDependencies。它指定了所依赖的layer,所有出现在指定layer中的模块,都不会被包含在当前模块中。例如,假设有2个页面P1和P2,他们所共用的代码被打包进layerA,各自特殊的则被打包进layerB和layerC。那么在描述layerB和layerC时就可以指定他们的layerDependencies为layerA,从而layerA中的代码只会被用户load一次,提高了加载速度。而所有的layer 都回隐含的依赖于标准的dojo.js layer。所以在dojo.js中出现的代码是不会出现在其它的layer中的。

除此之外,layer还支持以下可选属性:

copyrightFile 指定一个包含版权信息的文本文件,其内容将被包含在生成的layer文件中。
customBase 前面提到所有layer会依赖于标准的dojo.js。这个属性可以改变这个默认行为,改为依赖于一个定制的dojo.js。可能的场景是,你需要的是一个更小的dojo.js。比标准的小很多。
keepRequires 一个数组,包含需要在运行是require的模块。Dojo中可以用dojo.require()来引入一个module,在build的时候会直接在layer中引入这些module。如果你需要让某些文件需要时再require,可以在这个参数中指定。
discard 布尔类型。表示当前layer是否需要写入一个文件。默认为false,即一个layer当然要被写入一个单独的文件。但在某些情况下,一些layer只会作为其它layer的依赖而存在,这时此参数可以设置为true。

4.小结

bdBuild 是一个灵活、可扩展的开源build系统,使用JavaScript写成,并运行于Node.js, Rhino等JavaScript环境。非常适合前端人员创建自定义的打包过程。Dojo自带的build系统就是基于bdBuild,本文简要介绍了其原理和用法,虽然对于一般的Dojo开发这已经足够,但是如果要深入理解bdBuild,甚至开发其中的插件,仍然需要更多深入的了解。有兴趣的同学可以参考其文档,继续学习。

参考资料:


感谢张凯峰对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家加入到InfoQ中文站用户讨论组中与我们的编辑和其他读者朋友交流。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

很不错,感谢作者! by 囧 南风囧

呵呵,这个真好,dojo内容真的很丰富啊,这就是一个很好的在服务端用js的例子了!

新的build系统看起来不错 by Fu Cheng

使用node.js也算是与时俱进啊。

不错...dojo还是很喜欢的... by Lai Mead

不错...dojo还是很喜欢的...
可惜现在没有用...真是为性能发愁啊

不错, 知道有这么个好用的东西, 但是还是完全不会用... by Yun Chenge

不错, 知道有这么个好用的东西, 但是还是完全不会用...

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

4 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT