99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

基于Grunt構(gòu)建一個JavaScript庫

2018-06-16 16:20 更新

現(xiàn)在公認的JavaScript典型項目需要運行單元測試,合并壓縮。有些還會使用代碼生成器,代碼樣式檢查或其他構(gòu)建工具。

Grunt.js是一個開源工具,可以幫助你完成上面的所有步驟。它非常容易擴展,并使用JavaScript書寫,所以任何為JavaScript庫或項目工作的人都可以按自己的需要擴展它。

本文解釋如何使用Grunt.js構(gòu)建JavaScript庫。Grunt.js依賴Node.js和npm,所以第一節(jié)解釋其是什么,如何安裝和使用。如果你對npm有了解,那你可以跳過這一節(jié)。第四和第五節(jié)講述如何配置Grunt和一系列典型Grunt任務(wù)。

本文討論的代碼例子可以在GitHub上訪問。

工具概述(Tool Chain Overview)

開始之前,我們需要三個工具:

Node.js是一個流行的服務(wù)器端JavaScript環(huán)境。它被用來編寫和運行JavaScript服務(wù)和JavaScript命令行工具。如果你想進一步鏈接Node.js,你可以查看Stack Overflow上相關(guān)的資料。

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

Grunt.js是一個任務(wù)運行工具,我們用起構(gòu)建我們的項目。它在Node.js之上運行并且通過Npm安裝。

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

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

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

Linux

下載和使用安裝腳本。

Windows

windows安裝器包含npm并會添加path變量。僅在你下載Node.exe或從源代碼編譯Node是才需要獨立安裝Npm。從這里下載Npm的最新版zip壓縮包。解壓后賦值到Node.exe的安裝目錄。如果你愿意,你也可以放到任何位置,將其加入path變量即可。

OSX

安裝包中內(nèi)建Npm。

Npm基礎(chǔ)(Npm Basics)

了解Npm基礎(chǔ)操作對于使用和安裝Grunt.js都有幫助。這節(jié)僅包含接觸知識。更多細節(jié)可以查看npm文檔。

本節(jié)將解釋下面的東西:

  • 什么是npm;
  • npm插件本地安裝和全局安裝的區(qū)別;
  • package.json文件和其規(guī)范;
  • npm安裝命令。

概要(Overview)

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

項目通常在package.json文件內(nèi)部列出其依賴和安裝插件。此外npm庫也可以從命令行安裝。

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

每個包可以安裝在全局或本地環(huán)境。實際的區(qū)別是存儲位置和訪問方式。

全局安裝包被直接存儲在Node.js安裝路徑。他們之所以被稱為全局,是因為他們可以在任何地方直接訪問。

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

本地安裝包被存儲進node_mudules子目錄。無論你使用什么版本控制系統(tǒng),你可以將其添加僅.ignorefile 文件。

Package.json

package.json文件包含npm項目描述。它總是位于項目的根目錄,并且包含項目名稱,版本,協(xié)議和其他類似元數(shù)據(jù)。最重要的是,它包含兩個項目依賴列表。

 第一個列表包含運行所需要的依賴。任何希望使用此項目的人必須安裝它們。第二個列表包含開發(fā)時需要依賴項。包括測試工具,構(gòu)建工具和代碼樣式檢測工具。

創(chuàng)建package.json最簡單的方法是通過 npm install 命令。這條命令會以交互式提問一系列問題,并根據(jù)回答在當前工作目錄生成基本的package.json文件。只有名字(name)和版本(version)屬性是必須的。如果你不打算將你的庫發(fā)布到Npm,你能忽略其余的部分。

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

安裝命令(The Install Command)

Npm寶可以通過npm install 命令安裝。默認安裝到本地。全局安裝需要指定 -g開關(guān)。

不帶參數(shù)的 npm install 將在當前目錄或上層目錄查找 package.json 文件。如果發(fā)現(xiàn),將會在當前目錄安裝所有列出的依賴項。

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

版本號是可選的。如果省略將下載最新穩(wěn)定版。

最后,通過 –sace-dev開關(guān)不僅可以安裝包,還會將其添加到 package.json 的開發(fā)依賴中。

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

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

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

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

概論(Overview)

所有實際的工作是由任務(wù)運行器來做。命令行接口僅解析參數(shù)和將其傳遞個任務(wù)運行器。如果任務(wù)運行器沒有安裝將不會做任何事情。

命令行接口應(yīng)該被安裝在全局環(huán)境,然而任務(wù)運行器在本地環(huán)境。全局命令行接口保證Grunt命令可以在所有路徑訪問。任務(wù)運行器必須是本地的,因為不同的項目可能需要不同的Grunt版本。

安裝(Installation)

安裝全局Grunt命令行接口:

npm install -g grunt-cli

切換到項目根目錄,通過npm init讓Npm幫你生成package.json文件。它會問你些問題然后根據(jù)你的回答生成合法的package.json文件。只有名字和版本是必須的;你可以忽略其他選項。

將Grunt.js最新版添加到本地環(huán)境,同時添加到package.json文件的開發(fā)依賴里。

npm install grunt --save-dev

Package.json

通過前面的命令創(chuàng)建的package.json文件應(yīng)該類似相面這樣:

{
  "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運行任務(wù)并且通過任務(wù)完成工作。然而,Grunt.js安裝成功后還沒有任務(wù)可以使用。任務(wù)必須從插件載入,而插件通常需要Npm安裝。

我們使用五個插件:

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

本節(jié)將解釋如何配置這些插件。我們從最簡單的配置開始,然后一步步解釋如何配置任務(wù)。余下的子章節(jié)將詳細講解如何配置每個插件。

基礎(chǔ)-不做任何配置(Basic Do Nothing Configuration)

Grunt將配置信息寫到Gruntfile.js或Gruntfile.coffee文件里。由于我們創(chuàng)建的JavaScript項目,我們將使用JavaScript版本。最簡單的Gruntfile.js看起來像下面這樣:

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

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

配置信息被保存在module.exports函數(shù)內(nèi)部。它包含grunt對象作為其參數(shù),并且通過調(diào)用該函數(shù)完成配置。

配置函數(shù)必須創(chuàng)建至少一個任務(wù)別名,并且配置他們。例如,上面的代碼片段創(chuàng)建了一個“default”任務(wù)別名并且指定為空的任務(wù)列表。換句話說,默認的任務(wù)別名可以工作,但不會做任何事情。

用 grunt <taskAlias> 命令運行指定的 taskAlias任務(wù)。taskAlias的參數(shù)是可選的,如果省略,Grunt將使用“default”任務(wù)。

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

grunt

你應(yīng)該看到如下輸出:

Done, without errors.

如果配置任務(wù)返回錯誤或警告Grunt將發(fā)出蜂鳴聲(在命令行下輸入錯誤的聲音,譯者未發(fā)現(xiàn)這點)。如果你不想聽到蜂鳴聲,你可以使用 -no-color 參數(shù):

grunt -no-color

Grunt Npm 任務(wù)(Grunt Npm Tasks)

從插件添加任務(wù)是通過用步驟,對所有插件都是相同的。本節(jié)將概要講述需要的過程,實際的例子將在下面的章節(jié)講解。

安裝插件(Install the Plugin)

首先,我們需要將插件添加進package.json文件的開發(fā)依賴里面,并且使用Npm進行安裝:

npm install <plugin name> --save-dev

配置任務(wù)(Configure Tasks)

任務(wù)配置必須被存儲在一個對象內(nèi)部,有各自的任務(wù)名,并且被傳遞給 grunt.initConfig方法:

module.exports = function(grunt) {

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

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

全面的任務(wù)配置信息解釋看這里Grunt.js文檔。本節(jié)僅描述最通用,簡單的例子。假設(shè)任務(wù)接受一個文件列表,并處理他們,然后生出輸出文件。

一個簡單的任務(wù)配置例子:

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

例子中的任務(wù)配置有兩個屬性。一個是任務(wù)選項,名稱必須是”options“。Grunt.js不會對options的屬性執(zhí)行任何操作,其行為有插件決定。

其他項可以有任何名字,并且要包含任務(wù)目標。最常見的任務(wù)是操作和生成文件,所以他們的target有兩個屬性,”src“ 和 ”dest“。src包含輸入的文件列表,dest包含輸出的文件名字。

如果你配置多個任務(wù),Grunt將依次執(zhí)行。下面的任務(wù)將運行兩次,一次操作src及其子目錄的所有js文件,另一次操作test及其子目錄下的所有js文件:

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

加載和注冊任務(wù)(Load and Register Tasks)

最后,將插件載入必須使用 grunt.loadNpmTasks 函數(shù),并且注冊任務(wù)別名。

上面介紹的結(jié)構(gòu)合起來如下:

module.exports = function(grunt) {

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

};

配置JSHint(Configure JSHint)

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

我們將使用 grunt-contrib-jshint 插件,grunt-contrib開頭的插件都是有Grunt官方維護的,如果你創(chuàng)建自己的插件千萬不要以次開頭。

安裝插件(Install the Plugin)

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

JSHint參數(shù)(JSHint Options)

grunt-contrib-jshint插件的參數(shù)和JSHint一樣。完整的參數(shù)列表可以訪問JSHint的文檔頁面。

JSHint 的參數(shù) “eqeqeq” 會將 == 和 != 操作符報告為警告。默認是關(guān)閉的,因為這些操作符是合法的。但我建議你開啟它,因為嚴格相等比非嚴格相等更安全。

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

每一個可選項都是布爾值,設(shè)置為true將會開啟相應(yīng)檢測。下面的例子開啟了eqeqeq和trailing選項:

options: {
  eqeqeq: true,
  trailing: true
}

配置JSHint任務(wù)(Configure the JSHint Task)

grunt-contrib-jshint插件的任務(wù)名字是“jshint”。我們將使用上一節(jié)中的配置選項,使它檢測位于src和test目錄下的全部JavaScript文件。

JSHint的配置信息必須寫在名為“jshint”的屬性內(nèi)部??梢杂袃蓚€屬性,一個數(shù)參數(shù)(options)另一個是目標(target)。

目標可以在任何屬性內(nèi)部,在這里我們僅使用“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 任務(wù):

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的話),上線前我們必須將其打包進一個文件,并添加版本號和項目名字。在文件的開始位置應(yīng)該包含庫名稱,版本,協(xié)議,構(gòu)建時間和其他一些信息。

例如,像下面這樣:

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

我們將使用 grunt-contrib-concat 插件完成拼接任務(wù),并生成正確的注釋信息。

安裝插件(Install the Plugin)

和前面一樣,將插件寫進package.json文件的開發(fā)依賴里,然后從Npm倉庫安裝到本地。

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

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

加載Package.json(Load Package.json)

首先從package.json文件加載配置信息,并存儲在pkg屬性。需要使用 grunt.file.readJSON 函數(shù):

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

現(xiàn)在pkg的值是一個對象,包含全部package.json的信息。項目名被存儲在pkg.name屬性,版本被存儲在pkg.version。版權(quán)被存儲在pkg.license屬性等等。

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

Grunt提供一套模版系統(tǒng),我們可以使用它構(gòu)建頁頭和文件名稱。模版可以在字符串中嵌入JavaScript表達式,通過<%= expression %> 語法。Grunt計算表達式的值并替換模版中的表達式。

例如,模版中的 <%= pkg.name %> 將被替換為 pkg.name 的屬性值。如果屬性值是字符串,模版的行為類似字符串拼接 …’ + pkg.name + ‘…

模版中可以引用Grunt中的全部屬性。系統(tǒng)提供了一個非常有幫助的日期格式化函數(shù)。我們將使用 grunt.template.today(format) 函數(shù)生成當前的時間戳。

讓我們生成一個簡單的頁頭,包含項目名稱,版本號,版權(quán)和當前的日期。由于我們需要在 Uglify 任務(wù)中使用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支持通配符和模版,所以我們使用前一節(jié)生成的模版:

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。由于上面我們已經(jīng)將banner內(nèi)容賦給bannerContent變量,所以我們僅需引入即可:

options: {
  banner: bannerContent
}

加載和注冊(Load and Register)

最后不要忘記從Npm加載 grunt-contrib-concat ,并且將其注冊到默認工作流:

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

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

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

注意pkg屬性在傳遞給initConfig方法的參數(shù)中定義。我們不能把他放在其他地方,因為它讀取模版信息,并且僅在initConfig方法的參數(shù)和grunt對象中有訪問模版的權(quán)限。

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應(yīng)用程序而言,是必須要考慮的。

因此,我們也將我們庫進行壓縮。壓縮會將輸入的文件變小,通過去除空白元素,注釋,替換變量名稱等,但不會改變代碼邏輯。

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

源程序映射(Source Maps)

壓縮會使生成的文件難于閱讀和調(diào)試,所以我們通過生成源程序映射來簡化問題。

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

安裝插件(Install the Plugin)

將插件添加到package.json的開發(fā)依賴里,并且安裝到本地Npm倉庫。

使用如下命令:

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

配置目標(Configure Target)

配置uglify任務(wù)目標的方式和concat任務(wù)類似。必須要包含待壓縮的javascript文件列表和輸出文件的名字。

支持通配符和模版,所以我們可以使用前面章節(jié)中的用到的模版:

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一樣——通過設(shè)置“banner”屬性并且支持模版。因此,我們可以重復(fù)使用前面章節(jié)中準備好的 bannerContent 變量。

通過“sourceMap”屬性生成源文件映射。包含生成文件的名字。此外,必須設(shè)置“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,并且添加到默認任務(wù)列表:

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']);
};

最后的發(fā)布文件(Latest Release File)

最后要發(fā)布的庫包括兩個文件,并且都在名字中含有版本號。這會給想要自動下載每個新版本的人造成不必要的困難。

如果想要查看是否發(fā)布了新版本和新版本的名字,必須每次都要獲取和解析一個json文件。如果每次都更改名稱,則必須更新下載腳本。

因此我們將使用 grunt-contrib-copy 插件創(chuàng)建無版本號的文件。

安裝插件(Install the Plugin)

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

使用如下命令:

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

配置插件(Configure the Plugin)

copy配置信息包括三個目標,分別對應(yīng)三個發(fā)布文件。沒有配置選項,基本和前一個插件配置過程一樣。

僅有一點不一樣,就是多任務(wù)。每個任務(wù)包含一對 src/dest,待拷貝的名字和待創(chuàng)建的名字。

對前面的任務(wù)配置選項稍加修改。將所有文件名字放到變量中,以便可以重復(fù)使用:

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 運行單元測試,測試最新發(fā)布的文件。我們將使用 grunt-contrib-qunit 插件實現(xiàn)目標。這個插件將在無頭的 PhantomJS 實例中運行 QUnit 單元測試。

這個解決方案不能模擬不同瀏覽器和查找全部 bug,但對于我們來說已經(jīng)足夠了。如果想得到更好的配置,可以使用 js-test-driver 或 其他類似工具,然而,關(guān)于 js-test-dirver 的配置超出了本文的范圍。

準備測試用例(Prepare Tests)

Qunit 單元測試經(jīng)常要運行 src 目錄里的 JavaScript 文件,由于測試是開發(fā)的一部分。如果你想測試剛剛發(fā)布的拼接壓縮后的版本工作狀況,需要創(chuàng)建一個新的 QUnit HTML 文件,并加載最后發(fā)布的文件。

下面是一個例子是 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 的開發(fā)者依賴中,并且將其安裝到本地 Npm 倉庫。

使用如下命令:

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

配置插件(Configure Plugin)

配置 grunt-contrib-qunit 插件和配置前面的任務(wù)如出一轍。由于我們使用默認的 Qunit 配置,所以可以省略選項屬性。不能忽略的是必須配置 target,指定全部的 Qunit HTML 文件。

接下來指定位于測試目錄下的全部 HTML 文件,及其子目錄應(yīng)該運行 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']);
};

結(jié)論(Conclusion)

現(xiàn)在 Grunt.js 配置好了,并且可以使用了。我們的目標是使配置盡可能簡單,使用成對的 src/dest,通配符和模版。當然,Grunt.js 也提供其他更高級的選項。

如果能夠自動下載和管理項目依賴的庫,會變得更美好。我發(fā)現(xiàn)兩個可行的解決方案,BowerEnder。我沒有試過他們,但都可以管理前端JavaScript包和其依賴。

文章有些長,拖了很久的文章終于翻譯完成了,我最近打算寫一本關(guān)于 Grunt 指南的書籍,會詳細講解如何構(gòu)建一套前端自動化工具,如果你支持我的工作,那就給我捐助吧。

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

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號