何時我們需要 Dojo 的 build 工具
Dojo 作為一個非常實用的 Ajax 實現(xiàn)框架已經(jīng)被許多 web2.0 開發(fā)人員廣泛使用,但使用 Dojo 會導(dǎo)致客戶端瀏覽器需要加載大量的 Dojo 文件,導(dǎo)致應(yīng)用程序性能下降。解決 Dojo 性能問題的方法之一就是對 Dojo 文件進(jìn)行定制打包和壓縮 ( 提高 Dojo 性能的具體方案請參看“提高基于 Dojo 的 Web 2.0 應(yīng)用程序的性能”。Dojo 本身已經(jīng)提供了一套對 Dojo 庫文件 ( 自己編寫的 Javascript 文件只要符合 Dojo 的規(guī)范同樣可以進(jìn)行打包 ) 進(jìn)行 build 的工具,通過定制庫文件和壓縮文件的方法來減少瀏覽器加載文件的時間。
Dojo 的主要庫文件 (dojo 包 ) 大小在 1M 左右,dijit 包和 dojox 包大小都在 4M-5M,但我們并不總是需要所有的這些庫文件,可以根據(jù)開發(fā)者自身的需要定制一份 Dojo 庫,實際使用的庫文件大小往往能大大降低;以筆者目前的開發(fā)項目為例,經(jīng)過定制后實際使用的 Dojo 庫文件大小只有 300K 左右。
另外 Dojo 的 build 工具也通過壓縮 Javascript 文件的手段來降低瀏覽器加載文件的時間(該過程中需要使用 ShrinkSafe,有關(guān)其詳細(xì)介紹請參看“http://dojotoolkit.org/docs/shrinksafe”),具體的方法如下:
- 壓縮 Javascript 文件,包括:
- 刪除所有的空格和空行
- 刪除所有的注釋
- 將定義變量名用更簡短的字符代替
- 將所有打包的的 Javascript 文件的內(nèi)容合并為一個文件
經(jīng)過壓縮處理,Javascript 文件的大小總體可減少 30%-50%,同時將所有的 Javascript 文件打包成一個文件也減少了瀏覽器加載時多次開閉文件的負(fù)擔(dān),從而降低了加載時間。
準(zhǔn)備工作
- 到“dojo 下載網(wǎng)站”下載 Dojo 源代碼,下載后直接解壓即可,設(shè) Dojo 的解壓目錄為 \dojo(下文中皆用“\dojo”指代 Dojo 文件的解壓目錄);
- 下載并安裝 JDK( 盡量使用 1.5 以上的版本 ),設(shè)置 JAVA_HOME 環(huán)境變量;
jdk 下載地址:http://java.sun.com/javase/downloads/index.jsp
使用 Dojo 的 build 工具
Dojo 提供的 build 工具位于 \dojo\util\buildsrcipts 下,在 windows 下調(diào)用該目錄內(nèi)的 build.bat(linux 下使用 build.sh)文件既可執(zhí)行 build 工作。
下面是在一個在 windows 下調(diào)用 build.bat 的例子:
build profile=base action=release releaseName=myDojo optimize=shrinksafe
該命令中包括了幾個最常用的參數(shù),其意義如下:
- action: 指定本次命令的類型,提供的三個值是:clean, release, help;
- releaseName:本次 release 的名字,默認(rèn)為 dojo;
- optimize:本次 build 中進(jìn)行優(yōu)化的方式,一般使用 shrinksafe 既可;
- profile:指定 build 使用的 profile 文件,profile 文件中提供了 build 相關(guān)的配置信息,在 \dojo\util\buildsrcipts\profiles 目錄下有很多 *.profile.js 文件,我們自定義的 profile 文件也放在這個目錄下,例子中“profile=base”表示指定 base.profile.js 作為 build 的參數(shù)。
實際上在使用 Dojo 的 build 工具時,關(guān)鍵在于提供的 profile 文件里的內(nèi)容,在下面的例子中會詳細(xì)說明 profile 文件的配置方法。
定制 Dojo 文件
Dojo 庫中提供了大量的文件供使用者調(diào)用,但有的時候我們并不是需要所有的這些文件,此時我們可以使用 Dojo 的 build 工具定制一份個性化的 Dojo 庫文件,首先我們需要編寫一個 profile 文件來描述我們的需求:
清單 1. profile 文件配置示例 1
/* example.profile.js */ dependencies = { layers: [ // 可以根據(jù)需要制定多個不同的 layer { name: "example.js", // 打包生成的 js 文件的名 dependencies: [ // 需要打包的 js 文件列表 "dojo.date", "dojox.uuid" ] } ], prefixes: [ // 設(shè)置路徑 [ "dijit", "../dijit" ], [ "dojox", "../dojox" ] ] }
注意:
- dojo.js 是默認(rèn)被打包的,不需要在 dependencies中聲明
- 在 prefixes 設(shè)置路徑應(yīng)該是相對 dojo\dojo\dojo.js 的路徑,../dijit 實際上是 dojo\dijit
將該文件 (example.profile.js) 放在 \dojo\util\buildsrcipts\profiles 目錄下,執(zhí)行:
build profile=example action=release releaseName=myDojo optimize=shrinksafe
build 完成后,會在 \dojo 下生成一個 release 文件夾,如下圖所示:
圖示 1. build 后釋放的文件示意:

因為我們設(shè)置了 build 的參數(shù) releaseName=myDojo, 因此 release 下會生成一個 myDojo 文件夾,本次 build 產(chǎn)生的文件都置于該文件夾下。在 \dojo\release\myDojo\dojo\ 目錄下,我們可以找到兩個文件:example.js 和 example.uncompressed.js,這就是我們需要的打包后的文件,example.uncompressed.js 只是包含了我們指定的所有 dojo 文件,example.js 則在 example.uncompressed.js 基礎(chǔ)上又進(jìn)行了壓縮處理。
build 我們自己的 Javascript 文件
對于我們自己編寫的 Javascript 文件,我們同樣可是借助 Dojo 提供的 build 工具進(jìn)行壓縮和打包,前提是這些 js 文件需要按照 Dojo 相關(guān)的的規(guī)范編寫。打包我們自己的 Javascript 文件與打包 Dojo 文件并沒有太大的差別,假設(shè)我們有兩個 Javascript 文件如下:
清單 2. 假設(shè)需要打包的 2 個 Javascript 文件
/* my.example1 */ dojo.provide("my.example1"); dojo.require("my.example2"); // 聲明了對 my.example2 的依賴 /* * this is a js file witch named example1.js */ /* my.example2 */ dojo.provide("my.example2"); /* * this is a js file witch named example2.js */
在 \dojo 下新建一個文件夾“my”, 將上面的兩個文件放在該文件夾下,profile 文件配置如下:
清單 3. profile 文件配置示例 2
/* example.profile.js */ dependencies = { layers: [ { name: "example.js", dependencies: [ "dojo.date", "dojox.uuid", "my.example1" // 注意這里我們只聲明了 my.example1 ] } ], prefixes: [ [ "dijit", "../dijit" ], [ "dojox", "../dojox" ], [ "my", "../my"] // 剛才新建的 my 文件夾需要在此聲明路徑 ] }
執(zhí)行:
build.bat profile=example action=release releaseName=myDojo optimize=shrinksafe
請注意,在 profile 文件中,只聲明了將 my.example1 進(jìn)行打包,但在 build 生成的 example.js 中我們會發(fā)現(xiàn) my.example2 中的內(nèi)容也已經(jīng)被添加進(jìn)來了。這是因為在 build 過程中,build 程序在分析 js 文件內(nèi)容時通過識別一些關(guān)鍵字 ( 例如 dojo.require) 來判斷當(dāng)前文件是否依賴其他的文件,并將這些依賴的文件一同進(jìn)行打包。因此當(dāng) build 程序在 my.example1 中讀到 dojo.require("my.example2"); 時,判斷出該文件需要依賴另一個文件"my.example2",根據(jù) prefixes 提供的路徑 build 程序找到了 my.example2.js 文件,并將該文件的內(nèi)容添加進(jìn)來。
按照上面的例子 build 后,我們自己編寫的 Javascript 文件會和我們定制 Dojo 的文件合并在一個文件中,我們可能需要獨立使用這些自己編寫的 Javascript 文件,那么我們修改一下 profile 文件既可:
清單 4. profile 文件配置示例 3
/* example.profile.js */ dependencies = { layers: [ { // 這個 layer 用來打包我們定制的 dojo 文件 name: "mydojo.js", dependencies: [ "dojo.date", "dojox.uuid" ] }, { // 這個 layer 用于打包我們自己的 js 文件 name: "example.js", dependencies: [ "my.example1" ] } ], prefixes: [ [ "dijit", "../dijit" ], [ "dojox", "../dojox" ], [ "my", "../my"] ] }
執(zhí)行:
build.bat profile=example action=release releaseName=myDojo optimize=shrinksafe
這樣 build 后在 \dojo\release\myDojo\dojo\ 我們會分別得到 mydojo 和 example 兩個 layer 的打包文件:
- mydojo.js 和 mydojo.uncompressed.js:打包的是我們定制的 Dojo 文件
- example.js 和 example.uncompressed.js:打包了我們自己編寫 Javascript 文件,我們可以根據(jù)需要獨立使用他們
需要注意的問題
- 在上面我們已經(jīng)講到了 build 程序會按照 dojo.require 等關(guān)鍵字將依賴文件添加進(jìn)來,因此在每個 layer 的 dependencies 中我們不必列出所有我們需要打包的文件,只需要將一些根文件列出既可 ( 如清單 3 所示 );另外我們也應(yīng)該確保這些需要打包的文件以及他們所依賴的其他文件所在的路徑都在 prefixes 聲明注冊過,否則 build 程序會因為找不到所需要的文件而失敗。
- 上面提到在 build 過程中,會調(diào)用 shrinksafe 將 js 文件進(jìn)行壓縮,壓縮策略包括將定義的變量名用更為簡潔的字符串替代,例如我們定義
”var identifier”
,經(jīng)過壓縮處理可能就變成了”var _v01”
,。如果我們的 Javascript 代碼中使用了eval
語句,并且eval
的內(nèi)容里包含了一些我們定義的變量名,就會導(dǎo)致打包后的文件出現(xiàn)錯誤而無法使用。例如下面的 Javascript 代碼:
var identifier = “”; eval(“alert(identifier)”);
因為經(jīng)過壓縮后變量名 identifier 被 build 程序以其他的名字替代,因此在執(zhí)行 eval 方法 , 也就是調(diào)用 alert(identifier) 時,會因為無法識別 identifier 而報出 undefined 的錯誤。
小結(jié)
本文站在一個初學(xué)者的角度簡單地介紹了 Dojo 的 build 工具的使用方法(關(guān)鍵在于 profile 文件的配置),通過以上內(nèi)容讀者應(yīng)該能夠使用該工具進(jìn)行基本的定制和打包處理,有興趣的讀者可以通過提供的參考資料進(jìn)行進(jìn)一步的學(xué)習(xí)。