基於Grunt構建一個JavaScript庫

如今公認的JavaScript典型項目須要運行單元測試,合併壓縮。有些還會使用代碼生成器,代碼樣式檢查或其餘構建工具。javascript

Grunt.js是一個開源工具,能夠幫助你完成上面的全部步驟。它很是容易擴展,並使用JavaScript書寫,因此任何爲JavaScript庫或項目工做的人均可以按本身的須要擴展它。css

本文解釋如何使用Grunt.js構建JavaScript庫。Grunt.js依賴Node.js和npm,因此第一節解釋其是什麼,如何安裝和使用。若是你對npm有了解,那你能夠跳過這一節。第四和第五節講述如何配置Grunt和一系列典型Grunt任務。html

本文討論的代碼例子能夠在GitHub上訪問。前端

工具概述(Tool Chain Overview)

開始以前,咱們須要三個工具:html5

Node.js是一個流行的服務器端JavaScript環境。它被用來編寫和運行JavaScript服務和JavaScript命令行工具。若是你想進一步連接Node.js,你能夠查看Stack Overflow上相關的資料。java

Npm是Node.js的包管理工具。它能從中心倉庫下載依賴,解決大部分依賴衝突問題。Npm倉庫僅僅存儲Node.js服務器段和命令行項目。它不包含用於web和移動app相關的庫。咱們用它來下載Grunt.js。node

Grunt.js是一個任務運行工具,咱們用起構建咱們的項目。它在Node.js之上運行而且經過Npm安裝。git

安裝Node.js和Npm(Node.js and Npm Installation)

你能夠直接從下載頁面或用其它包管理工具安裝node.js。安裝成功後在命令行輸入 node -v Node.js將輸出它的版本號。github

大部分安裝器和包管理工具將同時安裝Npm。在命令行輸入 npm -v 測試是否安裝成功。若是成功將輸出它的版本號。不一樣的系統可能安裝方式略有不一樣。web

Linux

下載和使用安裝腳本

Windows

windows安裝器包含npm並會添加path變量。僅在你下載Node.exe或從源代碼編譯Node是才須要獨立安裝Npm。從這裏下載Npm的最新版zip壓縮包。解壓後賦值到Node.exe的安裝目錄。若是你願意,你也能夠放到任何位置,將其加入path變量便可。

OSX

安裝包中內建Npm。

Npm基礎(Npm Basics)

瞭解Npm基礎操做對於使用和安裝Grunt.js都有幫助。這節僅包含接觸知識。更多細節能夠查看npm文檔

本節將解釋下面的東西:

  • 什麼是npm;
  • npm插件本地安裝和全局安裝的區別;
  • package.json文件和其規範;
  • npm安裝命令。

概要(Overview)

Npm是一個包管理工具,能夠從中心倉庫下載和安裝JavaScript依賴。安裝包能被用在Node.js項目或命令行工具。

項目一般在package.json文件內部列出其依賴和安裝插件。此外npm庫也能夠從命令行安裝。

全局安裝vs本地安裝(Global vs Local Installation)

每一個包能夠安裝在全局或本地環境。實際的區別是存儲位置和訪問方式。

全局安裝包被直接存儲在Node.js安裝路徑。他們之因此被稱爲全局,是由於他們能夠在任何地方直接訪問。

本地安裝將下載包安裝在當前工做路徑。本地安裝包只能從其所在目錄訪問。

本地安裝包被存儲進node_mudules子目錄。不管你使用什麼版本控制系統,你能夠將其添加僅.ignorefile 文件。

Package.json

package.json文件包含npm項目描述。它老是位於項目的根目錄,而且包含項目名稱,版本,協議和其餘相似元數據。最重要的是,它包含兩個項目依賴列表。

 第一個列表包含運行所須要的依賴。任何但願使用此項目的人必須安裝它們。第二個列表包含開發時須要依賴項。包括測試工具,構建工具和代碼樣式檢測工具。

建立package.json最簡單的方法是經過 npm install 命令。這條命令會以交互式提問一系列問題,並根據回答在當前工做目錄生成基本的package.json文件。只有名字(name)和版本(version)屬性是必須的。若是你不打算將你的庫發佈到Npm,你能忽略其他的部分。

下面的連接包含對package.json的詳細描述:

安裝命令(The Install Command)

Npm寶能夠經過npm install 命令安裝。默認安裝到本地。全局安裝須要指定 -g開關。

不帶參數的 npm install 將在當前目錄或上層目錄查找 package.json 文件。若是發現,將會在當前目錄安裝全部列出的依賴項。

能夠經過 npm install <pkg_name@version> 命令安裝具體的npm包。這條命令將從中心倉庫找到指定版本的包,並將其安裝到當前目錄。

版本號是可選的。若是省略將下載最新穩定版。

最後,經過 --sace-dev開關不只能夠安裝包,還會將其添加到 package.json 的開發依賴中。

爲項目添加Grunt.js(Adding Grunt.js to the Project)

咱們將首先將Grunt.js添加進咱們的JavaScript項目。爲此咱們須要安裝兩個Grunt.js模塊:

  • grunt-cli - 命令行接口 (CLI);
  • grunt - 任務運行器.

提醒:最新的Grunt.js(4.0)再也不兼容之前的版本。一些老的教程和文檔再也不適合新版Grunt.js了。

概論(Overview)

全部實際的工做是由任務運行器來作。命令行接口僅解析參數和將其傳遞個任務運行器。若是任務運行器沒有安裝將不會作任何事情。

命令行接口應該被安裝在全局環境,然而任務運行器在本地環境。全局命令行接口保證Grunt命令能夠在全部路徑訪問。任務運行器必須是本地的,由於不一樣的項目可能須要不一樣的Grunt版本。

安裝(Installation)

安裝全局Grunt命令行接口:

npm install -g grunt-cli 

切換到項目根目錄,經過npm init讓Npm幫你生成package.json文件。它會問你些問題而後根據你的回答生成合法的package.json文件。只有名字和版本是必須的;你能夠忽略其餘選項。

將Grunt.js最新版添加到本地環境,同時添加到package.json文件的開發依賴裏。

npm install grunt --save-dev 

Package.json

經過前面的命令建立的package.json文件應該相似相面這樣:

{
  "name": "gruntdemo",
  "version": "0.0.0",
  "description": "Demo project using grunt.js.",
  "main": "src/gruntdemo.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": "",
  "author": "Meri",
  "license": "BSD",
  "devDependencies": {
    "grunt": "~0.4.1"
  }
}

 

配置Grunt.js(Configure Grunt.js)

Grunt.js運行任務而且經過任務完成工做。然而,Grunt.js安裝成功後尚未任務可使用。任務必須從插件載入,而插件一般須要Npm安裝。

咱們使用五個插件:

  • grunt-contrib-concat - 拼接文件,
  • grunt-contrib-uglify - 拼接並壓縮文件(js),
  • grunt-contrib-copy - 複製文件,
  • grunt-contrib-qunit - 運行單元測試,
  • grunt-contrib-jshint - 檢查bug和JavaScript代碼風格.

本節將解釋如何配置這些插件。咱們從最簡單的配置開始,而後一步步解釋如何配置任務。餘下的子章節將詳細講解如何配置每一個插件。

基礎-不作任何配置(Basic Do Nothing Configuration)

Grunt將配置信息寫到Gruntfile.js或Gruntfile.coffee文件裏。因爲咱們建立的JavaScript項目,咱們將使用JavaScript版本。最簡單的Gruntfile.js看起來像下面這樣:

//包裝函數 有一個參數
module.exports = function(grunt) {

  // 默認任務。在本例子中沒有任何操做。
  grunt.registerTask('default', []);
};

配置信息被保存在module.exports函數內部。它包含grunt對象做爲其參數,而且經過調用該函數完成配置。

配置函數必須建立至少一個任務別名,而且配置他們。例如,上面的代碼片斷建立了一個「default」任務別名而且指定爲空的任務列表。換句話說,默認的任務別名能夠工做,但不會作任何事情。

用 grunt <taskAlias> 命令運行指定的 taskAlias任務。taskAlias的參數是可選的,若是省略,Grunt將使用「default」任務。

保存Gruntfile.js文件,在命令行運行Grunt:

grunt

你應該看到以下輸出:

Done, without errors.

若是配置任務返回錯誤或警告Grunt將發出蜂鳴聲(在命令行下輸入錯誤的聲音,譯者未發現這點)。若是你不想聽到蜂鳴聲,你可使用 -no-color 參數:

grunt -no-color

Grunt Npm 任務(Grunt Npm Tasks)

從插件添加任務是經過用步驟,對全部插件都是相同的。本節將概要講述須要的過程,實際的例子將在下面的章節講解。

安裝插件(Install the Plugin)

首先,咱們須要將插件添加進package.json文件的開發依賴裏面,而且使用Npm進行安裝:

npm install <plugin name> --save-dev 

配置任務(Configure Tasks)

任務配置必須被存儲在一個對象內部,有各自的任務名,而且被傳遞給 grunt.initConfig方法:

module.exports = function(grunt) {

  grunt.initConfig({
    firstTask : { /* ... 配置第一個任務 ... */ },
    secondTask : { /* ... 配置第二個任務 ... */ },
    // ... 其餘任務 ...
    lastTask : { /* ... 最後一個任務 ... */ }
  });

  // ... the rest ... 
};

全面的任務配置信息解釋看這裏Grunt.js文檔。本節僅描述最通用,簡單的例子。假設任務接受一個文件列表,並處理他們,而後生出輸出文件。

一個簡單的任務配置例子:

firstTask: {
  options: {
    someOption: value //取決於插件
  },
  target: {
    src: ['src/file1.js', 'src/file2.js'], //輸入文件
    dest: 'dist/output.js' // 輸出文件
  }
}

例子中的任務配置有兩個屬性。一個是任務選項,名稱必須是」options「。Grunt.js不會對options的屬性執行任何操做,其行爲有插件決定。

其餘項能夠有任何名字,而且要包含任務目標。最多見的任務是操做和生成文件,因此他們的target有兩個屬性,」src「 和 」dest「。src包含輸入的文件列表,dest包含輸出的文件名字。

若是你配置多個任務,Grunt將依次執行。下面的任務將運行兩次,一次操做src及其子目錄的全部js文件,另外一次操做test及其子目錄下的全部js文件:

multipleTargetsTask: {
  target1: { src: ['src/**/*.js'] },
  target2: { src: ['test/**/*.js']] }
} 

加載和註冊任務(Load and Register Tasks)

最後,將插件載入必須使用 grunt.loadNpmTasks 函數,而且註冊任務別名。

上面介紹的結構合起來以下:

module.exports = function(grunt) {

  grunt.initConfig({ /* ... tasks configuration ... */ });
  grunt.loadNpmTasks('grunt-plugin-name');
  grunt.registerTask('default', ['firstTask', 'secondTask', ...]);

};

 

配置JSHint(Configure JSHint)

JSHint檢查JavaScript代碼中潛在的問題和錯誤。他被設計成可配置的,而且有合理的默認值。

咱們將使用 grunt-contrib-jshint 插件,grunt-contrib開頭的插件都是有Grunt官方維護的,若是你建立本身的插件千萬不要以次開頭。

安裝插件(Install the Plugin)

打開命令行,在項目根目錄運行 npm install grunt-contrib-jshint --save-dev。將會添加插件到package.json文件的開發依賴,而且安裝到本地Npm倉庫。

JSHint參數(JSHint Options)

grunt-contrib-jshint插件的參數和JSHint同樣。完整的參數列表能夠訪問JSHint的文檔頁面

JSHint 的參數 「eqeqeq」 會將 == 和 != 操做符報告爲警告。默認是關閉的,由於這些操做符是合法的。但我建議你開啓它,由於嚴格相等比非嚴格相等更安全。

同時我建議你開啓trailing選項,將會對代碼中結尾部的空白元素生成警告。結尾的空白在多行字符串中會引發奇怪的問題。

每個可選項都是布爾值,設置爲true將會開啓相應檢測。下面的例子開啓了eqeqeq和trailing選項:

options: {
  eqeqeq: true,
  trailing: true
} 

配置JSHint任務(Configure the JSHint Task)

grunt-contrib-jshint插件的任務名字是「jshint」。咱們將使用上一節中的配置選項,使它檢測位於src和test目錄下的所有JavaScript文件。

JSHint的配置信息必須寫在名爲「jshint」的屬性內部。能夠有兩個屬性,一個數參數(options)另外一個是目標(target)。

目標能夠在任何屬性內部,在這裏咱們僅使用「target」。其必須包含待驗證的JavaScript文件列表。文件列表能夠放在目標的src屬性中,可使用**和*通配符。

有兩個自定義選項,將會驗證位於src和test目錄及其子目錄下的全部js文件。

grunt.initConfig({
  jshint: {
    options: {
      eqeqeq: true,
      trailing: true
    },
    target: {
      src : ['src/**/*.js', 'test/**/*.js']
    }
  }
});

 

加載和註冊(Load and Register)

最後須要載入和註冊 grunt-contrib-jshint 任務:

grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.registerTask('default', ['jshint']);

 

所有JSHint配置選項(Full JSHint Configuration)

目前爲止完整的 Gruntfile.js 文件以下:

module.exports = function(grunt) {

  grunt.initConfig({
    jshint: {
      options: {
        trailing: true,
        eqeqeq: true
      },
      target: {
        src : ['src/**/*.js', 'test/**/*.js']
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.registerTask('default', ['jshint']);
};

 

拼接文件(Concatenate Files)

js文件通常是分散的(若是你的項目不是幾十行js的話),上線前咱們必須將其打包進一個文件,並添加版本號和項目名字。在文件的開始位置應該包含庫名稱,版本,協議,構建時間和其餘一些信息。

例如,像下面這樣:

/*! gruntdemo v1.0.2 - 2013-06-04
 *  License: BSD */
var gruntdemo = function() {
  ...

 咱們將使用 grunt-contrib-concat 插件完成拼接任務,並生成正確的註釋信息。

安裝插件(Install the Plugin)

和前面同樣,將插件寫進package.json文件的開發依賴裏,而後從Npm倉庫安裝到本地。

打開命令行,運行以下命令: 

npm install grunt-contrib-concat --save-dev

加載Package.json(Load Package.json)

首先從package.json文件加載配置信息,並存儲在pkg屬性。須要使用 grunt.file.readJSON 函數:

pkg: grunt.file.readJSON('package.json'),

如今pkg的值是一個對象,包含所有package.json的信息。項目名被存儲在pkg.name屬性,版本被存儲在pkg.version。版權被存儲在pkg.license屬性等等。

生成頁頭信息和 文件名(Compose Banner and File Name)

Grunt提供一套模版系統,咱們可使用它構建頁頭和文件名稱。模版能夠在字符串中嵌入JavaScript表達式,經過<%= expression %> 語法。Grunt計算表達式的值並替換模版中的表達式。

例如,模版中的 <%= pkg.name %> 將被替換爲 pkg.name 的屬性值。若是屬性值是字符串,模版的行爲相似字符串拼接 ...' + pkg.name + '...

模版中能夠引用Grunt中的所有屬性。系統提供了一個很是有幫助的日期格式化函數。咱們將使用 grunt.template.today(format) 函數生成當前的時間戳。

讓咱們生成一個簡單的頁頭,包含項目名稱,版本號,版權和當前的日期。因爲咱們須要在 Uglify 任務中使用banner,因此咱們將其存儲在變量中:

var bannerContent = '/*! <%= pkg.name %> v<%= pkg.version %> - ' +
                    '<%= grunt.template.today("yyyy-mm-dd") %> \n' +
                    ' *  License: <%= pkg.license %> */\n';

上面的模版生成以下的頁頭:

/*! gruntdemo v0.0.1 - 2013-06-04
 *  License: BSD */ 

項目的名稱和版本部分也須要在多處使用。將項目名和版本號拼在一塊兒,存儲在一個變量中:

var name = '<%= pkg.name %>-v<%= pkg.version%>'; 

生成的名字以下:

gruntdemo-v0.0.1

配置目標和選項(Configure Target and Options)

target必須包含須要被拼接的文件列表,和合並完成後輸出文件的名字。target支持通配符和模版,因此咱們使用前一節生成的模版:

target : {
  // 拼接src目錄下的全部文件
  src : ['src/**/*.js'],
  // place the result into the dist directory,
  // name variable contains template prepared in
  // previous section
  dest : 'distrib/' + name + '.js'
}

concat插件也能夠經過banner屬性添加banner。因爲上面咱們已經將banner內容賦給bannerContent變量,因此咱們僅需引入便可:

options: {
  banner: bannerContent
}

加載和註冊(Load and Register)

最後不要忘記從Npm加載 grunt-contrib-concat ,而且將其註冊到默認工做流:

grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('default', ['jshint', 'concat']);

完整的拼接配置(Full Concat Configuration)

這一節出示包含完整contat配置的Gruntfile.js文件。

注意pkg屬性在傳遞給initConfig方法的參數中定義。咱們不能把他放在其餘地方,由於它讀取模版信息,而且僅在initConfig方法的參數和grunt對象中有訪問模版的權限。

module.exports = function(grunt) {
  var bannerContent = '... banner template ...';
  var name = '<%= pkg.name %>-v<%= pkg.version%>';

  grunt.initConfig({
    // pkg is used from templates and therefore
    // MUST be defined inside initConfig object
    pkg : grunt.file.readJSON('package.json'),
    // concat configuration
    concat: {
      options: {
        banner: bannerContent
      },
      target : {
        src : ['src/**/*.js'],
        dest : 'distrib/' + name + '.js'
      }
    },
    jshint: { /* ... jshint configuration ... */ }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.registerTask('default', ['jshint', 'concat']);
};

 

壓縮(Minify)

若是瀏覽器載入和解析大文件,會使頁面載入變得緩慢。可能不是全部項目都會遇到這個問題,但對於移動端的app和使用很是多大型庫的大型web應用程序而言,是必需要考慮的。

所以,咱們也將咱們庫進行壓縮。壓縮會將輸入的文件變小,經過去除空白元素,註釋,替換變量名稱等,但不會改變代碼邏輯。

壓縮功能使用 grunt-contrib-uglify 插件,其經過Grunt集成 UglifyJs。它經過uglify任務拼接和壓縮一組文件。

源程序映射(Source Maps)

壓縮會使生成的文件難於閱讀和調試,因此咱們經過生成源程序映射來簡化問題。

源程序映射是壓縮文件和源文件之間的紐帶。若是瀏覽器支持,瀏覽器調試工具會顯示對人友好的源文件,而不是壓縮文件。僅有chrome和nightly版本的 firefox支持源代碼映射。你能夠在HTML5 rocksTutsplus 上獲取更多信息,我建議你看看阮一峯老師的這篇文章:http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html

安裝插件(Install the Plugin)

將插件添加到package.json的開發依賴裏,而且安裝到本地Npm倉庫。

使用以下命令:

npm install grunt-contrib-uglify --save-dev

 

配置目標(Configure Target)

配置uglify任務目標的方式和concat任務相似。必需要包含待壓縮的javascript文件列表和輸出文件的名字。

 支持通配符和模版,因此咱們可使用前面章節中的用到的模版:

target : {
  // use all files in src directory
  src : ['src/**/*.js'],
  // place the result into the dist directory,
  // name variable contains template prepared in
  // previous sub-chapter
  dest : 'distrib/' + name + '.min.js'
}

 

配置選項(Configure Options)

配置banner的方式和concat同樣——經過設置「banner」屬性而且支持模版。所以,咱們能夠重複使用前面章節中準備好的 bannerContent 變量。

經過「sourceMap」屬性生成源文件映射。包含生成文件的名字。此外,必須設置「sourceMapUrl」和「sourceMapRoot」屬性。前一個包含相對於uglified文件到源文件映射文件的路徑,後一個包含是源文件映射到源文件的相對路徑。

 經過bannerContent變量生成頁眉,經過name變量生成源文件映射文件的名字:

options: {
  banner: bannerContent,
  sourceMapRoot: '../',
  sourceMap: 'distrib/'+name+'.min.js.map',
  sourceMapUrl: name+'.min.js.map'
}

 

加載和註冊(Load and Register)

最後一步是從Npm加載 grunt-contrib-uglify,而且添加到默認任務列表:

grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', ['jshint', 'concat', 'uglify']);

 

所有 Uglify 配置信息(Full Uglify Configuration)

下面是包含完整uglify配置信息的Gruntfile.js文件:

module.exports = function(grunt) {
  var bannerContent = '... banner template ...';
  var name = '<%= pkg.name %>-v<%= pkg.version%>';  

  grunt.initConfig({
    // pkg must be defined inside initConfig object
    pkg : grunt.file.readJSON('package.json'),
    // uglify configuration
    uglify: {
      options: {
        banner: bannerContent,
        sourceMapRoot: '../',
        sourceMap: 'distrib/'+name+'.min.js.map',
        sourceMapUrl: name+'.min.js.map'
      },
      target : {
        src : ['src/**/*.js'],
        dest : 'distrib/' + name + '.min.js'
      }
    },
    concat: { /* ... concat configuration ... */ },
    jshint: { /* ... jshint configuration ... */ }
  });
   
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
};

 

最後的發佈文件(Latest Release File)

最後要發佈的庫包括兩個文件,而且都在名字中含有版本號。這會給想要自動下載每一個新版本的人形成沒必要要的困難。

若是想要查看是否發佈了新版本和新版本的名字,必須每次都要獲取和解析一個json文件。若是每次都更更名稱,則必須更新下載腳本。

所以咱們將使用 grunt-contrib-copy 插件建立無版本號的文件。

安裝插件(Install the Plugin)

將插件添加進package.json的開發依賴,而且從Npm倉庫安裝到本地。

使用以下命令:

 npm install grunt-contrib-copy --save-dev

 

配置插件(Configure the Plugin)

copy配置信息包括三個目標,分別對應三個發佈文件。沒有配置選項,基本和前一個插件配置過程同樣。

僅有一點不同,就是多任務。每一個任務包含一對 src/dest,待拷貝的名字和待建立的名字。

 對前面的任務配置選項稍加修改。將全部文件名字放到變量中,以即可以重複使用:

module.exports = function(grunt) {
  /* define filenames */
  latest = '<%= pkg.name %>';
  name = '<%= pkg.name %>-v<%= pkg.version%>';

  devRelease = 'distrib/'+name+'.js';
  minRelease = 'distrib/'+name+'.min.js';
  sourceMapMin = 'distrib/source-map-'+name+'.min.js';

  lDevRelease = 'distrib/'+latest+'.js';
  lMinRelease = 'distrib/'+latest+'.min.js';
  lSourceMapMin = 'distrib/source-map-'+latest+'.min.js';

  grunt.initConfig({
    copy: {
      development: { // copy non-minified release file
        src: devRelease,
        dest: lDevRelease
      },
      minified: { // copy minified release file
        src: minRelease,
        dest: lMinRelease
      },
      smMinified: { // source map of minified release file
        src: sourceMapMin,
        dest: lSourceMapMin
      }
    },
    uglify: { /* ... uglify configuration ... */ },
    concat: { /* ... concat configuration ... */ },
    jshint: { /* ... jshint configuration ... */ }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'copy']);

 

單元測試(Unit Tests)

最後,配置 grunt.js 運行單元測試,測試最新發布的文件。咱們將使用 grunt-contrib-qunit 插件實現目標。這個插件將在無頭的 PhantomJS 實例中運行 QUnit 單元測試。

這個解決方案不能模擬不一樣瀏覽器和查找所有 bug,但對於咱們來講已經足夠了。若是想獲得更好的配置,可使用 js-test-driver 或 其餘相似工具,然而,關於 js-test-dirver 的配置超出了本文的範圍。

準備測試用例(Prepare Tests)

Qunit 單元測試常常要運行 src 目錄裏的 JavaScript 文件,因爲測試是開發的一部分。若是你想測試剛剛發佈的拼接壓縮後的版本工做情況,須要建立一個新的 QUnit HTML 文件,並加載最後發佈的文件。

下面是一個例子是 Qunit 的入口文件:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>QUnit Example</title>
  <link rel="stylesheet" href="../libs/qunit/qunit.css">
</head>
<body>
  <div id="qunit"></div>
  <div id="qunit-fixture"></div>
  <script src="../libs/qunit/qunit.js"></script>

  <!-- Use latest versionless copy of current release -->
  <script src="../distrib/gruntdemo.min.js"></script>
  <script src="tests.js"></script>
</body>
</html>

 

安裝插件(Install the Plugin)

將插件添加進package.json 的開發者依賴中,而且將其安裝到本地 Npm 倉庫。

使用以下命令:

npm install grunt-contrib-qunit --save-dev

 

配置插件(Configure Plugin)

配置 grunt-contrib-qunit 插件和配置前面的任務一模一樣。因爲咱們使用默認的 Qunit 配置,因此能夠省略選項屬性。不能忽略的是必須配置 target,指定所有的 Qunit HTML 文件。

接下來指定位於測試目錄下的所有 HTML 文件,及其子目錄應該運行 Qunit 測試:

grunt.initConfig({
  qunit:{
    target: {
      src: ['test/**/*.html']
    }
  },
  // ... all previous tasks ...
});

 

完整的 Grunt.js 文件(Final Grunt.js File)

下面是完整的 Gruntfile.js 配置信息:

module.exports = function(grunt) {
  var name, latest, bannerContent, devRelease, minRelease,
      sourceMap, sourceMapUrl, lDevRelease, lMinRelease,
      lSourceMapMin;
 
  latest = '<%= pkg.name %>';
  name = '<%= pkg.name %>-v<%= pkg.version%>';
  bannerContent = '/*! <%= pkg.name %> v<%= pkg.version %> - ' +
    '<%= grunt.template.today("yyyy-mm-dd") %> \n' +
    ' *  License: <%= pkg.license %> */\n';
  devRelease = 'distrib/'+name+'.js';
  minRelease = 'distrib/'+name+'.min.js';
  sourceMapMin = 'distrib/'+name+'.min.js.map';
  sourceMapUrl = name+'.min.js.map';
 
  lDevRelease = 'distrib/'+latest+'.js';
  lMinRelease = 'distrib/'+latest+'.min.js';
  lSourceMapMin = 'distrib/'+latest+'.min.js.map';
   
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    qunit:{
      target: {
        src: ['test/**/*.html']
      }
    },
    // configure copy task
    copy: {
      development: {
        src: devRelease,
        dest: lDevRelease
      },
      minified: {
        src: minRelease,
        dest: lMinRelease
      },
      smMinified: {
        src: sourceMapMin,
        dest: lSourceMapMin
      }
    },
    // configure uglify task
    uglify:{
      options: {
        banner: bannerContent,
        sourceMapRoot: '../',
        sourceMap: sourceMapMin,
        sourceMappingURL: sourceMapUrl
      },
      target: {
        src: ['src/**/*.js'],
        dest: minRelease
      }
    },
    // configure concat task
    concat: {
      options: {
        banner: bannerContent
      },
      target: {
        src: ['src/**/*.js'],
        dest: devRelease
      }
    },
    // configure jshint task
    jshint: {
      options: {
        trailing: true,
        eqeqeq: true
      },
      target: {
        src: ['src/**/*.js', 'test/**/*.js']
      }
    }
  });
 
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-qunit');
 
  grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'copy', 'qunit']);
};

 

結論(Conclusion)

如今 Grunt.js 配置好了,而且可使用了。咱們的目標是使配置儘量簡單,使用成對的 src/dest,通配符和模版。固然,Grunt.js 也提供其餘更高級的選項

若是可以自動下載和管理項目依賴的庫,會變得更美好。我發現兩個可行的解決方案,Bower Ender。我沒有試過他們,但均可以管理前端JavaScript包和其依賴。

文章有些長,拖了好久的文章終於翻譯完成了,我最近打算寫一本關於 Grunt 指南的書籍,會詳細講解如何構建一套前端自動化工具,若是你支持個人工做,那就給我捐助吧。

原文:http://flippinawesome.org/2013/07/01/building-a-javascript-library-with-grunt-js/

相關文章
相關標籤/搜索