翻译 - 【Dojo Tutorials】Creating Builds

Dojo的编译系统(build,后称编译)提供了一种编译Dojo和你的其他JavaScript代码与CSS文件的方式,让你的应用在生产环境可以高效的利用它们。

“编译”Dojo或JavaScript?

如果你使用过其他编程语言,你也许会纳闷为什么我们要探讨Dojo或JavaScript的“编译”问题,因为编译通常意味着是将代码编译成机器语言。但是当我们谈论Dojo的编译时讲的是这么一个概念,将代码最小化,优化性能,代码串联与移除没用的代码。

每当你从服务器发送代码到客户端来解释执行时,如JavaScript,HTML和CSS,它都将花费带宽与时间。你发送了多少,取决与向服务器发送了多少请求。与你的代码执行快慢无关,因为在浏览器加载完之前还无法开始执行代码。

Dojo编译器是一个可以让代码在客户端运行更高效的工具,包括自定义代码,模块与CSS。如果处理得当,你可以为你的应用创建一个易管理与维护的编译系统。

基础

Dojo的编译系统可以很复杂,且是高定制化的。它被设计成可扩展的,虽然本教程没有讲到它。另外,新的编译系统在Dojo 1.7引入,且对之前的版本做了向后兼容,它几乎完全被重写,很多情况下它可以做的更好,以至于让你不用再看编译后的代码,尤其是当你在应用中使用AMD语法时。

在开始之前,有几个贯穿本教程的核心概念需要来理解一下。

模块与包

但愿你在查看本教程之前已经理解了模块的概念。如果没有,你应该先看看定义模块的教程,它是Dojo 1.10的基础。模块被组织成包,把逻辑相关的模块组在一起。在Dojo 1.10中,每个包都应该有个描述包的package.json文件。很多包还应有package.js文件,用于提供Dojo指定的编译信息。

Dojo配置

内在的,Dojo有很多配置项可以在应用中使用。配置不仅在应用运行时显得重要,它还影响应用的编译,潜在的提供这些配置作为编译处理的部分。如果你还不熟悉Dojo的配置,你应用先看看使用dojoConfig配置Dojo

层本质上是一个单独的JavaScript文件,包含了几个模块,有时候是其他资源。一个层通常是你要查找的编译输出,创建这个文件后你的应用就变为可分发的了。一个层可以是一个启动层,它包含Dojo的启动代码,允许Dojo载入其他模块。你拥有什么层及它里面是什么内容,这取决与你的应用与设计,没有一个统一的方式。

编译配置文件

编译配置文件是一个很小的JavaScript文件,它为编译器提供了改如何编译代码的信息。在就的编译系统中,有一个配置,在util/buildscripts/profiles目录下,包含了你需要的所有东西。从Dojo 1.7开始,变得较为灵活分散了,每个包都应该有个编译配置,然后应该还有一个主配置告诉编译器那些包和层应该编译,同样也可以提供优化代码的配置。

最小化

这个概念是将JavaScript代码压缩的更小,且保持原用功能。从效率的角度来看这是很棒的,一些开发者喜欢这样混淆代码,但是那样使调试变得困难。这是一个你不想开发编译的代码的原因。Dojo编译器使用两个工具来实现最小化。首先是ShrinkSafe,它只可以压缩1.7之前的代码。1.7之后的代码,编译使用Google的Closure Compiler

移除无用代码

Google Closure Compiler的一个最大优势就是可以检测出不被执行到的代码,在压缩版本中将它们删除。几年前,我们启动了一个叫Dojo Linker的项目以解决类似的问题,但一直没有时间来完成它,所以有个可选方案我们很开心。Dojo设计时曾构思过该功能。有些“把手”在编译的时候可以设置,使编译器在路径中“硬编码”到输出代码中,当开始优化的时候,Closure Compiler检测那些执行不到的代码并删除它们,以达到缩小文件的目的。

编译控制,传输与分析器

它们都是编译系统的基础编译块。你不需要特意的去了解他们,但是如果你对高级编译感兴趣,可以修改它们来做些有趣的事情。编译控制是编译指令的集合,读取配置来决定要使用什么传输与分析器。传输就是做些如它字面上所说的,谈论一些东西然后传输到其他东西上;分析器是编译时解决AMD插件模块。例如,如果你使用dojo/text加载一个挂件模板,编译时会将模板文件放入压缩文件中。

你需要什么

为了使用Dojo的编译系统,你必须有完整的Dojo SDK。标准版已经使用编译系统编译过的。编译工具自身依赖于Java(与可选的快速方案:Node.js),所以要确保这些依赖你已经安装好了。

布置你的应用

这是组大的一个挑战,尤其是当你要超越基础应用时。我们注意那些从Dojo 1.6甚至更早版本迁移过来的人有一个与我们预期相差深远的应用结构。这意味着有相当多的人要面对迁移他们应用到1.7或者更新版本的挑战。所以在你还没有深入完成你的应用的时候,你需要考虑一些你的文件结构。

在根目录有个类似src的文件夹装着所有的包。大概看起这样:

Dojo的主要(dojo,dijit和dojox)包与其他包在同一级目录,包括你的自定义包,加上Dojo的工具包(util)。

如果你不像一点点来布置,Dojo Boilerplate有你需要运行的一切,不仅仅是基础的应用框架,而是已经配置的可以直接编译。

未来使用编译系统来编译,应用的包目录中必须有两个文件。首先是一个CommonJS Packages/1.0包描述,通常命名为package.json,放置在包的根目录。第二个就是编译配置文件,包含有描述让编译工具如何处理包的内容。这个两个主要约定的命名文件。在Dojo工具集中,它被命名为<packagename>.profile.js且放置在包的根目录。这有个替代方案,就是包配置文件命名为package.js放置在包的根目录下。在Dojo功能包中将会看到这种做法。

有一点需要说明,你必须把你的整个应用代码放置在一个包中,如果有需要把你的代码分开(如为了代码重用,给拆分成了shared/common模块),你需要为它们每个包创建这些文件。

包描述

包描述文件(package.json)提供了当前包的一些信息,如包名,依赖包,认证许可和bug追踪等等。对于编译系统而言,比较关键的是键dojoBuild,最好提供一个名字,版本和描述。dojoBuild用于指向包的编译配置文件。例如一个名为app的包,它的描述文件package.js如下:

 1 {
 2     "name": "app",
 3     "description": "My Application.",
 4     "version": "1.0",
 5     "keywords": ["JavaScript", "Dojo", "Toolkit", "DojoX"],
 6     "maintainers": [{
 7         "name": "Kitson Kelly"
 8     }],
 9     "contributors": [{
10         "name": "Kitson Kelly"
11     },{
12         "name": "Colin Snover"
13     }],
14     "licenses": [{
15         "type": "AFLv2.1",
16         "url": "http://bugs.dojotoolkit.org/browser/dojox/trunk/LICENSE#L43"
17     },{
18         "type": "BSD",
19         "url": "http://bugs.dojotoolkit.org/browser/dojox/trunk/LICENSE#L13"
20     }],
21     "bugs": "https://github.com/example/issues",
22     "repositories": [{
23         "type": "git",
24         "url": "http://github.com/example.git",
25         "path": "packages/app"
26     }],
27     "dependencies": {
28         "dojo": "~1.10.3",
29         "dijit": "~1.10.3",
30         "dojox": "~1.10.3"
31     },
32     "main": "src",
33     "homepage": "http://example.com/",
34     "dojoBuild": "app.profile.js"
35 }

CommonJS Packages/1.0提供了包描述可能选项的全部列表。如果你的代码只是内部使用,你可以将它精简,但最起码要有dojoBuild选项。

包编译配置

包编译配置文件是编译系统的主要配置。它是一个JavaScript文件,用于构建一个配置对象,包含创建功能齐全的应用的指令。一个基本的编译配置看起来像这个样子:

1 var profile = (function(){
2     return {
3         resourceTags: {
4             amd: function(filename, mid) {
5                 return /\.js$/.test(filename);
6             }
7         }
8     };
9 })();

注意我们执行了一个匿名函数。这可以确保环境中的其他代码不会影响你的配置文件。这也给了你机会来更灵活的生成包含计算的配置对象。

编译配置由dojoBuild连接,如果它不是应用的主编译配置,只需要包含resourceTags指令即可。

这提供了编译器编译你的包的最小化信息。至于编译器读取这个包的时候发生了什么,将每个文件都交由resourceTags的函数来决策它是否接收处理。这些函数有两个参数,文件名与模块ID。如果函数返回true这个这个标签被应用(当然返回false的时候就不应用)。

标记这些js结尾的文件为AMD模块,编译器同样会处理它们,而不会假定他们是遗留的Dojo模块。这里还有些其他的标记,需要你想用它们来标记你的资源:

amd

AMD模块资源

declarative

这个资源用于声明标记,你想要为依赖而扫描的包。

test

这个资源是包测试代码的一部分。

copyOnly

这个资源只需要复制到目标目录即可,其他的都保持不变。

miniExclude

如果已经是最小化的资源了,则不需要复制到目标目录。

如果你没有标记你的模块为amd,但它确实是的,编译器会提示这个模块是AMD并继续处理,但最好能明确的标记你的代码。

使用declarative标记已经超过了本教程的范围。关于它的更多信息请参阅参考指南depsDeclarative

确定你适当的标记了你的资源用于编译器适当的处理他们是很重要的。我们假设你在目录src/app/tests下放置了测试代码(因为所有好的程序猿都会为他的包做单元测试,不是吗?),加上profile.json与一些其他类型的文件我想要只复制它们。所以一个更完整的配置应该是这样的:

 1 var profile = (function(){
 2     var testResourceRe = /^app\/tests\//,
 3         // checks if mid is in app/tests directory
 4
 5         copyOnly = function(filename, mid){
 6             var list = {
 7                 "app/app.profile": true,
 8                 // we shouldn‘t touch our profile
 9                 "app/package.json": true
10                 // we shouldn‘t touch our package.json
11             };
12             return (mid in list) ||
13                 (/^app\/resources\//.test(mid)
14                     && !/\.css$/.test(filename)) ||
15                 /(png|jpg|jpeg|gif|tiff)$/.test(filename);
16             // Check if it is one of the special files, if it is in
17             // app/resource (but not CSS) or is an image
18         };
19
20     return {
21         resourceTags: {
22             test: function(filename, mid){
23                 return testResourceRe.test(mid) || mid=="app/tests";
24                 // Tag our test files
25             },
26
27             copyOnly: function(filename, mid){
28                 return copyOnly(filename, mid);
29                 // Tag our copy only files
30             },
31
32             amd: function(filename, mid){
33                 return !testResourceRe.test(mid)
34                     && !copyOnly(filename, mid)
35                     && /\.js$/.test(filename);
36                 // If it isn‘t a test resource, copy only,
37                 // but is a .js file, tag it as AMD
38             }
39         }
40     };
41 })();

正如你看到的,你可以很快很复杂,但是这个概念的本质是,配置文件需要一个包含resourceTags的哈希,包含了代表不同标记的函数集。你可以利用强大的JavaScript来为不同的资源指派对应的标记。

对于单独的包配置文件,以及如何标记它的资源,你可以看看dgrid的配置文件。

应用编译配置

为了把一个包进一个编译版本,你只需要完成上面说的这些,标记你的资源。但是如果想要创建一个有利于生成环境的编译版本,我们还需要一些其他选项。有两种做法,如果你的应该只有一个简单的包,包含了所有的自定义代码,你也许想要在应用中创建一个全的包配置文件。如果你的应用比较复杂且有多个包,或者你想要为不同的编译设置不同的编译配置,你应该创建一个应用配置文件。

接下来的教程,我们假定你要创建一个应用级别的配置,叫做myapp.profile.js,在应用的根目录下放着。

一些用于为创建全的编译配置的结构的关键选项如下:

Option Type Description
basePath Path 这是编译的根目录,接下类的编译都从这里开始计算。关联编译配置的文件位置。
releaseDir Path 编译目标目录,编译器会覆盖它发现的一切,与basePath相关联。
releaseName String
它作为发行版本的输出名称。它跟随在releaseDir之后。例如,如果你要释放代码到release/prd中,设置releaseDir为release,

设置releaseName为prd 

action String 应该设置为release
packages Array 编译器使用到的模块。用于灵活的指向其他地方的模块,在编译的时候和自定义代码放在一起。
layers Object 允许创建不同的层模块作为编译版本的一部分,把谨慎的功能编译进一个单独的文件。

假如我们要构建一个应用配置,我们有两个文件想要载入到单页应用中。一个是我们代码的依赖,另一个是在某种情况下根据需要载入:

 1 var profile = (function(){
 2     return {
 3         basePath: "./src",
 4         releaseDir: "../../app",
 5         releaseName: "lib",
 6         action: "release",
 7
 8         packages:[{
 9             name: "dojo",
10             location: "dojo"
11         },{
12             name: "dijit",
13             location: "dijit"
14         },{
15             name: "dojox",
16             location: "dojox"
17         },{
18             name: "app",
19             location: "app"
20         }],
21
22         layers: {
23             "dojo/dojo": {
24                 include: [ "dojo/dojo", "dojo/i18n", "dojo/domReady",
25                     "app/main", "app/run" ],
26                 customBase: true,
27                 boot: true
28             },
29             "app/Dialog": {
30                 include: [ "app/Dialog" ]
31             }
32         }
33     };
34 })();

如果我们现在编译这个配置,会如何呢,会在app/lib下包含我们四个包的模块,加上两个特殊命名的文件app/lib/dojo/dojo.js和app/lib/app/Dialog.js,它们包含了它们需要的模块的编译版本。

这里我们忽略了层的复杂性,后面我们会深入了解它。

编译优化

移除不会被执行到的代码

缺省配置

把他们放到一起

编译

总结

其他资源

时间: 2024-08-26 07:02:42

翻译 - 【Dojo Tutorials】Creating Builds的相关文章

dojo 官方翻译 dojo/json 版本1.10

官方地址:http://dojotoolkit.org/reference-guide/1.10/dojo/json.html#dojo-json require(["dojo/json", "dojo/dom", "dojo/on", "dojo/domReady!"], function(JSON, dom, on){ on(dom.byId("convert"), "click",

dojo 官方翻译 dojo/_base/lang 版本1.10

官方地址:http://dojotoolkit.org/reference-guide/1.10/dojo/_base/lang.html#dojo-base-lang 应用加载声明: require(["dojo/_base/lang"], function(lang){ // lang now contains the module features }); clone() 克隆任何对象或者元素节点,返回:一个新的对象. require(["dojo/_base/lang

dojo 官方翻译 dojo/domReady 版本1.10

官方地址:http://dojotoolkit.org/reference-guide/1.10/dojo/domReady.html#dojo-domready dom加载完成后,执行. require(["dojo/domReady!"], function(){ // will not be called until DOM is ready }); 通常dojo/domReady没有也不需要设定一个返回值,而且,它是被放在加载模块数组的最后加载. require(["

dojo 官方翻译 dojo/string 版本1.10

官方地址:http://dojotoolkit.org/reference-guide/1.10/dojo/string.html#dojo-string require(["dojo/string"], function(string){ var a = string.pad("pad me", 10); var b = string.rep("dup", 10); var c = string.substitute("${repla

dojo 官方翻译 dojo/_base/array

官方地址:http://dojotoolkit.org/reference-guide/1.10/dojo/_base/array.html#dojo-base-array array模块dojo进行了很好的封装,如果想要调用必须先加载该模块: require(["dojo/_base/array"], function(array){ // array contains the features }); indexOf() 返回值:字符串在数组中第一次出现的位置,如果没有找到默认返回

翻译 - 【Dojo Tutorials】Creating Template-based Widgets

原文:Creating Template-based Widgets 在本教程中,你将学习Dijit的_TemplatedMixin混入类的重要性与如何利用模版快速创建你自己的自定义挂件. 开始 如果你不熟悉如何创建Dijit挂件,你也许需要想看看理解_Widgets教程.创建自定义挂件教程与编写你自己的挂件教程也或帮助你学习如何创建挂件. Dijit的_WidgetBase为创建挂件提供了优秀的基础架构,但是_TemplatedMixin混合类才是Dijit闪耀的所在.使用_Templated

翻译 - 【Dojo Tutorials】Part 5 - Build FlickrView for production

原文:Part 5 - Build FlickrView for production 在前面的几篇文章中,我们通过编写HTML, CSS和JavaScript实现了这个FlickrView移动应用.本片文章将专注于为部署更新代码,利用Dojo的构建系统让生产环境应用保持紧凑,并回顾了整个Dojo Mobile驱动的应用. Dojo Mobile与构建 为Dojo Mobile应用创建一个构建版本是很重的,因为我们想要我们的应用尽可能的小.让我们看逐步了解一下如何创建我们Dojo Mobile应

翻译 - 【Dojo Tutorials】Dojo Object Store

关注分离是良好编程的基础.保持展示与数据的分离是关键.受到HTML5存储API的启发,Dojo对象存储架构为数据交互建立了统一的接口. 为什么要使用Dojo对象存储? 关注分离是有组织,可管理程序的基础,在web应用中分离点主要是指数据与用户接口(在MVC架构中用户接口通常是指试图和控制器).受到HTML5存储API的启发,Dojo对象存储架构为数据交互建立了统一的接口.这些API是为促进松耦合的开发为存在的,可以让挂件和用户接口从多种源以一致的的方式与数据交互. Dojo对象存储允许你开发和使

翻译 - 【Dojo Tutorials】Application Controller

原文:Application Controller 一个页面级别的控制器就像胶水,通过将模块化的功能黏在一起来构造一个鲜活的应用.我们将实现配置与一个明确的生命周期,通过松耦合的架构组合一个单页面应用的多个部分. 介绍 作为一个模块化的工具包,很多Dojo的文档都是在讲解单独的组件如何使用.但是当你需要组合它们来创建一个应用的时候,你需要一个框架来将它们灵活的组织起来. 问题 最佳实践建议保持关注点分离,维护组成应用的模块.所以,如何管理各个组件的加载与初始化,如何将它们与数据结合起来,用户界面