本文主要介紹前端開發中經常使用的構建工具Grunt,具體包括Grunt的基本狀況、安裝、使用和常見插件的安裝、配置和使用等內容。css

1.1 Grunt簡單介紹

Grunt是一套前端自動化構建工具。對於須要反覆重複的任務(如壓縮、編譯、單元測試等),自動化構建工具能夠減輕並簡化咱們的工做。咱們只須要在 Gruntfile 文件中正確配置好要處理的任務,任務運行器就會自動幫咱們完成大部分工做。前端

Grunt的優勢java

❏ Grunt擁有龐大的生態系統,而且一直在增加。
❏ Grunt支持咱們本身創做插件併發布。node

因爲Grunt擁有數量龐大的插件,因此幾乎任何的任務均可以利用Grunt來自動完成,你也能夠根據本身項目的特色來創做合適的插件發佈。webpack

Grunt的工做方式git

Grunt爲開發者提供了一個工具包,用於建立命令行程序來執行項目構建過程當中的重複性任務,好比壓縮js代碼、編譯Sass樣式等。Grunt不只僅能建立簡單任務以解決特定工程遇到的特定需求,還能將任務打包爲可複用的插件。這些插件能夠被髮布、分享,使用以及被其餘人進行改進。github

Grunt的運轉依賴於四個核心的組件:分別是Gruntfile、Tasks 、Plugins以及任務配置。web

   ① Gruntfile    express

Gruntfile指的是在項目根目錄下面名爲Gruntfile.js的Node模塊。該文件使得咱們能夠加載Grunt插件,建立自定義任務,並根據項目需求對它們進行配置。npm

Grunt每次運行時的首要任務都是接受該模塊發出的指令。

   ② Tasks    

Tasks做爲Grunt的基本構建模塊,它其實是由Grunt的registerTask()方法註冊的具名函數。

   ③ Plugins    

Plugins是一系列可以用於不一樣項目的可配置任務的集合。

   ④ 任務配置    

Grunt強調配置優先,任務和插件的功能均可以經過配置文件進行定製,以適應不一樣工程的需求。這種代碼和配置相分離的特性,使開發者可以創造出高複用的插件。

相關參考

如今最新版本     v1.0.2
其它構建工具     gulp、webpack、fis3等

Grunt官網
Grunt官網(中文)
Grunt相關的插件列表

1.2 Grunt的安裝

Grunt和相關的插件都經過 npm 安裝並管理。

Grunt基於Node.js,安裝以前要先安裝Node.js。

Node.js的安裝

① 打開Node.js官網找到Download選項,選擇對應的版本下載。
② 下載以後,根據對應的提示進行安裝便可。
③ 安裝完成以後,能夠經過$ node --version$ npm --version命令查看是否安裝成功。

wendingding:~ wendingding$ node --version
v8.9.3
wendingding:~ wendingding$ npm --version
5.5.1
wendingding:~ wendingding$

❗ ️Grunt依賴於nodejs的v0.8.0及以上版本;

安裝注意點

❗ ️奇數版本號的 Node.js 被認爲是不穩定的開發版;
❗️ 需確保當前環境中所安裝的 npm 已是最新版本($ npm update -g npm

安裝Grunt命令行

注意 在使用Grunt以前,須要先安裝Grunt命令行到全局環境中。

安裝命令:$ npm install -g grunt-cli

安裝完以後,能夠經過$ grunt命令來驗證Grunt命令行是否安裝完成並生效,命令行中的-g表示全局安裝。

具體的執行狀況

wendingding:~ wendingding$ npm install -g grunt-cli
/usr/local/bin/grunt -> /usr/local/lib/node_modules/grunt-cli/bin/grunt
+ grunt-cli@1.2.0
added 16 packages in 9.289s
wendingding:~ wendingding$ grunt
grunt-cli: The grunt command line interface (v1.2.0)
 
Fatal error: Unable to find local grunt.
 
If you're seeing this message, grunt hasn't been installed locally to
your project. For more information about installing and configuring grunt,
please see the Getting Started guide:
 
http://gruntjs.com/getting-started

Grunt命令行的做用 

Grunt命令行用於調用與Gruntfile在同一目錄中 Grunt。每次運行Grunt 時,都會根據node提供的require()系統查找本地安裝的 Grunt(所以咱們能夠在項目的任意子目錄中運行grunt) ,若是找到一份本地安裝的 Grunt,命令行就將其加載,並傳遞Gruntfile中的配置信息,而後執行指定的任務。

1.3 Grunt的安裝和使用

1.3.1 Grunt使用的基本步驟

Grunt使用的基本步驟

①  生成package.json和Gruntfile.js文件
②  命令行安裝項目中須要用到的插件
③  編輯Gruntfile文件定義Task並進行配置
④  命令行以grunt task的方式執行任務

1.3.2 Grunt的安裝

接下來,咱們經過一個完整的Grunt案例來介紹Grunt的常規使用方法。首先建立的對應的項目文件目錄,這裏命名爲Grunt_demo文件夾,而後建立package.json文件Gruntfile.js文件並進行相關配置,安裝相應的插件並執行Task。

   ① 建立package.json文件   

建立package.json文件有兩種方式,一種是直接建立而後以json格式的字段來進行配置,第二種是經過執行npm install來建立,推薦經過命令行的方式來建立。

✧ 直接建立package.json文件 ✧

wendingding:~ wendingding$ mkdir Grunt_Demo
wendingding:~ wendingding$ cd Grunt_Demo/
wendingding:Grunt_Demo wendingding$ PWD
/Users/文頂頂/Grunt_Demo
wendingding:Grunt_Demo wendingding$ touch package.json
wendingding:Grunt_Demo wendingding$ open package.json

$ mkdir Grunt_Demo 表示建立文件夾命令行說明

$ cd Grunt_Demo/ 表示進入文件目錄

$ PWD 表示查看當前路徑

$ touch package.json 表示建立package.json文件

$ open package.json 表示使用記事本打開文件並編輯

wendingding:Grunt_Demo wendingding$ open package.json
wendingding:Grunt_Demo wendingding$ cat package.json
{
"name":"Grunt_Demo",
"version":"1.0.0",
"dependencies":{}
}

建立好package.json文件後,能夠根據須要添加內容字段到文件中。該json文件中最基本字段主要有name、version和dependencies,其中name和version對應的是Grunt項目的名稱和版本,而dependencies字段中則列出該項目的依賴。$ cat package.json 表示查看文件內容

package.json文件用於被npm存儲項目的元數據,以便將此項目發佈爲npm模塊。咱們能夠在此文件中列出項目依賴的Grunt和Grunt插件,保存在devDependencies(開發依賴)配置段內。

✧ 初始化命令建立package.json文件 ✧

除手動建立外,咱們還可以經過命令行來進行初始化操做,會以交互的方式來生成一個包含基本配置信息的package.json文件。

初始化命令:$ npm init

下面列出具體的命令行執行狀況

wendingding:Grunt_Demo wendingding$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
 
See `npm help json` for definitive documentation on these fields
and exactly what they do.
 
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
 
Press ^C at any time to quit.
package name: (grunt_demo)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /Users/文頂頂/Grunt_Demo/package.json:
 
{
"name": "grunt_demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
 
 
Is this ok? (yes) yes
wendingding:Grunt_Demo wendingding$ cat package.json
{
"name": "grunt_demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

package.json文件注意點在執行npm init命令建立基本package.json文件的時候,能夠設置名稱、版本、依賴等選項,若是不設置直接回車表示以默認(建議)的方式來進行配置。

❐ package.json應當放置於項目的根目錄中,並同項目源代碼一塊兒管理。
❐ 若是在根目錄中運行npm install命令,那麼將依據package.json列出的依賴項來自動安裝適當版本的依賴。

   ② 建立Gruntfile文件   

Gruntfile文件是Grunt項目中最核心的文件,能夠被命名爲 Gruntfile.js 或者是Gruntfile.coffee,該文件同package.json文件一塊兒存放在項目的根目錄中,主要用來配置或定義任務(task)並加載Grunt插件

標準的grunt項目中必須擁有package.json和Gruntfile這兩個文件。

wendingding:Grunt_Demo wendingding$ touch Gruntfile.js
wendingding:Grunt_Demo wendingding$ tree -L 2
.
├── Gruntfile.js
└── package.json
 
0 directories, 2 files

   ③ 安裝Grunt    $ tree -L 2 表示以樹狀圖的方式列出當前目錄下面的二級文件結構,具體使用能夠參考網絡編程系列 Mac系統中Tree的使用

在建立Grunt項目的過程當中,咱們能夠經過$ npm install <module> --save-dev模式的命令來安裝Grunt和Grunt插件。該命令在安裝的同時,會自動將其添加到package.json文件的devDependencies 配置段中。

接下來咱們演示安裝Grunt最新版本到項目目錄中,並將其添加到devDependencies內。

命令行:$ npm install grunt --save-dev

wendingding:Grunt_Demo wendingding$ npm install grunt --save-dev
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN grunt_demo@1.0.0 No description
npm WARN grunt_demo@1.0.0 No repository field.
 
+ grunt@1.0.2
added 94 packages in 33.833s

命令行執行完畢以後,會發現package.json的配置段中信息發生了變動,在devDependencies配置項中增長了grunt字段和對應的版本信息。

wendingding:Grunt_Demo wendingding$ cat package.json
{
"name": "grunt_demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"grunt": "^1.0.2"
}
}

項目的根目錄中增長了node_modules文件中,該目錄列出了必要的依賴文件,下面給出文件結構。 

 1 wendingding:Grunt_Demo wendingding$ tree -L 2
 2 .
 3 ├── Gruntfile.js
 4 ├── node_modules
 5 │ ├── abbrev
 6 │ ├── ansi-regex
 7 │ ├── ansi-styles
 8 │ ├── argparse
 9 │ ├── array-find-index
10 │ ├── async
11 │ ├── balanced-match
12 │ ├── brace-expansion
13 │ ├── builtin-modules
14 │ ├── camelcase
15 │ ├── camelcase-keys
16 │ ├── chalk
17 │ ├── coffeescript
18 │ ├── colors
19 │ ├── concat-map
20 │ ├── currently-unhandled
21 │ ├── dateformat
22 │ ├── decamelize
23 │ ├── error-ex
24 │ ├── escape-string-regexp
25 │ ├── esprima
26 │ ├── eventemitter2
27 │ ├── exit
28 │ ├── find-up
29 │ ├── findup-sync
30 │ ├── fs.realpath
31 │ ├── get-stdin
32 │ ├── getobject
33 │ ├── glob
34 │ ├── graceful-fs
35 │ ├── grunt
36 │ ├── grunt-known-options
37 │ ├── grunt-legacy-log
38 │ ├── grunt-legacy-log-utils
39 │ ├── grunt-legacy-util
40 │ ├── has-ansi
41 │ ├── hooker
42 │ ├── hosted-git-info
43 │ ├── iconv-lite
44 │ ├── indent-string
45 │ ├── inflight
46 │ ├── inherits
47 │ ├── is-arrayish
48 │ ├── is-builtin-module
49 │ ├── is-finite
50 │ ├── is-utf8
51 │ ├── isexe
52 │ ├── js-yaml
53 │ ├── load-json-file
54 │ ├── lodash
55 │ ├── loud-rejection
56 │ ├── map-obj
57 │ ├── meow
58 │ ├── minimatch
59 │ ├── minimist
60 │ ├── nopt
61 │ ├── normalize-package-data
62 │ ├── number-is-nan
63 │ ├── object-assign
64 │ ├── once
65 │ ├── parse-json
66 │ ├── path-exists
67 │ ├── path-is-absolute
68 │ ├── path-type
69 │ ├── pify
70 │ ├── pinkie
71 │ ├── pinkie-promise
72 │ ├── read-pkg
73 │ ├── read-pkg-up
74 │ ├── redent
75 │ ├── repeating
76 │ ├── resolve
77 │ ├── rimraf
78 │ ├── safer-buffer
79 │ ├── semver
80 │ ├── signal-exit
81 │ ├── spdx-correct
82 │ ├── spdx-exceptions
83 │ ├── spdx-expression-parse
84 │ ├── spdx-license-ids
85 │ ├── sprintf-js
86 │ ├── strip-ansi
87 │ ├── strip-bom
88 │ ├── strip-indent
89 │ ├── supports-color
90 │ ├── trim-newlines
91 │ ├── underscore.string
92 │ ├── validate-npm-package-license
93 │ ├── which
94 │ └── wrappy
95 ├── package-lock.json
96 └── package.json
97  
98 91 directories, 3 files


1.3.3 Grunt插件的安裝和使用

至此,Grunt項目的基本配置以及Grunt的安裝已經完成,在開發中使用Grunt主要是用Grunt相關的一些插件來實現特定的功能。Grunt的生態中提供了很是豐富的插件,咱們能夠直接在官方搜索查看,接下來給你們介紹幾個在前端項目構建中經常使用到的插件。

✧ 文件合併插件concat的安裝和使用 ✧

concat插件的地址:https://github.com/gruntjs/grunt-contrib-concat

concat插件安裝命令:$ npm install grunt-contrib-concat --save-dev

--save-dev參數表示插件安裝完成後,記錄相關信息到package.json文件中的devDependencies配置項。

下面列出具體的執行狀況

 1 wendingding:Grunt_Demo wendingding$ npm install grunt-contrib-concat --save-dev
 2 npm WARN grunt_demo@1.0.0 No description
 3 npm WARN grunt_demo@1.0.0 No repository field.
 4  
 5 + grunt-contrib-concat@1.0.1
 6 added 2 packages in 3.165s
 7 wendingding:Grunt_Demo wendingding$ cat package.json
 8 {
 9 "name": "grunt_demo",
10 "version": "1.0.0",
11 "description": "",
12 "main": "index.js",
13 "scripts": {
14 "test": "echo \"Error: no test specified\" && exit 1"
15 },
16 "author": "",
17 "license": "ISC",
18 "devDependencies": {
19 "grunt": "^1.0.2",
20 "grunt-contrib-concat": "^1.0.1"
21 }
22 }

插件安裝完成後,在項目的node_modules文件目錄會新增長grunt-contrib-concat模塊。接下來咱們經過編輯Gruntfile文件來定義和配置Task。 

在項目的根目錄中建立src文件夾,在該文件夾下面建立兩個示例的js文件,分別爲demo_one.js和demo_two.js

demo_one.js文件的內容

1 //聲明demoOne函數並執行
2 function demoOne() {
3 console.log("demoOne.js文件中的內容");
4 }
5 demoOne();

demo_two.js文件的內容 

1 //聲明demoTwo函數並執行
2 function demoTwo() {
3 console.log("demoTwo.js文件中的內容");
4 }
5 demoTwo();

編輯Gruntfile文件定義和配置Task 

接下來咱們須要編輯Gruntfile文件,在該文件中告訴grunt具體的任務(Task)是什麼,以及這些任務(Task)應該如何執行,下面給出示例代碼

 1 //包裝函數,規定全部的代碼都須要寫在該函數內部
 2 module.exports = function (grunt) {
 3  
 4 //項目配置信息
 5 grunt.initConfig({
 6 //表示從package文件中加載json數據,並保存到pkg屬性中
 7 pkg:grunt.file.readJSON("package.json"),
 8 //concat任務的配置信息
 9 "concat":{
10 dist: {
11 //把src目錄下面的demo_one和demo_two文件合併成demo.js文件保存到dist目錄
12 src: ['src/demo_one.js', 'src/demo_two.js'],
13 dest: 'dist/demo.js',
14 }
15 }
16  
17 })
18  
19 //加載包含concat任務的插件
20 grunt.loadNpmTasks("grunt-contrib-concat");
21  
22 //設置默認執行的任務列表
23 grunt.registerTask("default",["concat"]);
24 };

上面的示例代碼主要由三部分組成:配置任務相關代碼 + 加載插件相關代碼 + 註冊任務相關代碼,全部的代碼都須要寫在module.exports這個包裝函數內部,grunt做爲包裝函數的參數傳遞。

代碼說明

這裏代碼中的pkg部分並不是必要,loadNpmTasks方法用於從node_modules中加載對應的插件,registerTask方法表示把concat這個任務加入到默認的任務隊列中(該行代碼並不是必需),若是不寫該行代碼則能夠直接以$ grunt concat的方式執行合併任務。固然也能夠經過registerTask方法來給Task註冊個別名,而後經過$ grunt 別名指令來執行該Task。

當前的目錄結構以下(注:省略node_modules目錄細節)

wendingding:Grunt_Demo wendingding$ tree -L 1
.
├── Gruntfile.js
├── node_modules
├── package-lock.json
├── package.json
└── src
  ├── demo_one.js
  └── demo_two.js

不一樣插件的使用方式可能也不盡相同,插件的具體用法請參考對應的文檔說明。經過編輯Gruntfile文件指定任務的配置項、加載插件並註冊任務後,就能夠經過命令行來執行Task了。 

執行Task

執行Task的命令行:$ grunt 或者是$ grunt default 或者是$ grunt concat
命令行輸出結果

wendingding:Grunt_Demo wendingding$ grunt default
Running "concat:dist" (concat) task
 
Done.

Task執行結束後,src目錄下面的demo_one.js和demo_two.js兩個文件會被合併成demo.js文件並保存到dist目錄下,若是指定的目錄不存在那麼將會直接建立。 

✧ 壓縮插件uglify和cssmin的安裝和使用 ✧

建立新的文件目錄Grunt_Test來演示javaScript的壓縮插件uglify以及CSS的壓縮插件cssmin的使用,建立好文件目錄以後,一樣經過$ npm init初始化命令來生成基礎的package.json文件。

先安裝grunt到本地的項目中,具體命令以下:

$ npm install grunt --save-dev

而後下載須要用到的對應插件到本地的項目中,具體命令以下 :

$ npm install grunt-contrib-uglify --save-dev 表示安裝uglify插件

$ npm install grunt-contrib-cssmin --save-dev 表示cssmin插件

上面的命令行執行完畢後,grunt就會把兩個壓縮插件下載到node_modules文件目錄下,能夠經過在該目錄下查找grunt-contrib-uglify和grunt-contrib-cssmi文件進行驗證。

--save--dev參數會把下載記錄更新到package.json文件中的devDependencies字段。

"devDependencies": {
"grunt": "^1.0.2",
"grunt-contrib-cssmin": "^2.2.1",
"grunt-contrib-uglify": "^3.3.0"
}

爲了演示壓縮插件的具體使用,下面咱們在項目根目錄下建立index.js文件,並新建style文件夾,並在該目錄下建立index.css文件,具體的目錄結構以下:

.
├── node_modules
│ ├── ...(省略)
│ ├── grunt-contrib-cssmin
│ ├── grunt-contrib-uglify
├── package-lock.json
├── package.json
└── src
  ├── index.js
  └── style
└── index.css

index.js文件內容爲 

 1 /**
 2 * Created by wendingding on 18/5/19.
 3 */
 4  
 5 var a = 123;
 6 var b = "文頂頂";
 7 function sum(a,b) {
 8 return a + b;
 9 }
10  
11 (function (c) {
12 console.log("______" + c);
13 })(window);

index.css文件內容爲 

body{
background: red;
}
*{
margin: 0;
padding: 0;
list-style: none;
}

接下來咱們建立並編輯Gruntfile文件,經過特定的代碼定義和配置Task。 

 1 //包裝函數
 2 module.exports = function (grunt) {
 3  
 4 var app = {
 5 src:"src/",
 6 dist:"dist/"
 7 };
 8  
 9 //(1) 項目配置信息
10 //說明:initConfig方法等價於grunt.config.init()方法;
11 grunt.initConfig({
12 //定義js文件壓縮Task: 表示把src目錄下面的index.js文件壓縮到dist目錄中的index.min.js
13 "uglify":{
14 target:{
15 src:app.src + "index.js",
16 dest:app.dist + "index.min.js"
17 }
18 },
19 //定義css文件壓縮Task: 表示把src/style目錄中的index.css文件壓縮到dist目錄中的index.min.css
20 "cssmin":{
21 target:{
22 src:app.src + "style/index.css",
23 dest:app.dist + "index.min.css"
24 }
25 }
26 });
27  
28 //(2) 加載對應的插件
29 grunt.loadNpmTasks("grunt-contrib-uglify");
30 grunt.loadNpmTasks("grunt-contrib-cssmin");
31  
32 //(3) 註冊任務
33 //002 註冊任務的第一種方式
34 //① 這種方式能夠不寫任何註冊任務相關的代碼
35 //② 咱們能夠經過$ grunt uglify和$ grunt cssmin命令來分別執行這兩個Task
36 //③ 支持以$ grunt uglify cssmin的方式來依次執行多個Task
37  
38 //002 註冊任務的第二種方式
39 //① 這種方式至關於給每一個任務都起一個Task名稱,經過$ grunt task名稱的方式執行
40 //② 執行命令 $ grunt uglifyTask 表示執行js文件的壓縮操做
41 //③ 執行命令 $ grunt cssminTask 表示執行css文件的壓縮操做
42 //④ 執行命令 $ grunt cssminTask uglifyTask 表示先執行css文件的壓縮,再執行js文件的壓縮
43 //grunt.registerTask("uglifyTask","uglify");
44 //grunt.registerTask("cssminTask","cssmin");
45  
46 //003 註冊任務的第三種方式
47 // ① 這種方式把多個任務添加到default任務隊列中,執行$ grunt default的時候,全部的Task依次執行
48 // ② 執行命令爲 $ grunt default 或者是$ grunt 由於default能夠被省略
49 // grunt.registerTask("default",["uglify","cssmin"]);
50 };

根據任務註冊的不一樣方式來執行Task,下面分別給出三種方式的執行命令 

方式(1)先執行$ grunt cssmin再執行 $ grunt uglify,或者經過$ grunt cssmin uglify命令來依次執行多個任務。

方式(2)先執行$ grunt cssminTask再執行 $ grunt uglifyTask,或者經過$ grunt cssminTask uglifyTask命令來依次執行多個任務。

方式(3)經過$ grunt或者是$ grunt default命令來依次執行多個任務。

wendingding:Grunt_Test wendingding$ grunt default
Running "uglify:target" (uglify) task
>> 1 file created 174 B → 93 B
 
Running "cssmin:target" (cssmin) task
>> 1 file created. 89 B → 57 B
 
Done.

當兩個任務執行完畢後,項目中會建立dist目錄,該目錄中新增兩個文件分別對應壓縮版的js文件和壓縮版的css文件,新的目錄結構以下。 

.
├── node_modules
│ ├── ...(省略)
│ ├── grunt-contrib-cssmin
│ ├── grunt-contrib-uglify
├── package-lock.json
├── package.json
├── dist
│ ├── index.min.js
│ └── index.min.css
└── src
├── index.js
└── style
└── index.css

上文列出了代碼合併插件concat和壓縮插件uglify|uglify的安裝和基本使用過程,grunt生態系統擁有數量龐大的高質量插件羣體,沒法一一介紹,能夠到Grunt相關的插件列表頁面-中文Grunt相關的插件列表頁面-官網自行查看。 

Grunt插件使用總結

❏ 建立package.json文件(簡單配置)和Gruntfile文件($ npm init)
❏ 經過命令行把Grunt下載和安裝到本地項目中($ npm install grunt --save-dev)
❏ 經過命令行把Grunt插件下載和安裝到本地項目中($ npm install grunt-contrib-xxx)
❏ 在Gruntfile文件中對Grunt插件的Task進行配置(grunt.initConfig)
❏ 在Gruntfile文件中經過代碼來加載對應的插件(grunt.loadNpmTasks)
❏ 在Gruntfile文件中經過代碼來註冊任務(grunt.registerTask)
❏ 在命令行中經過grunt + 任務名的方式來執行Task或加入到default隊列以grunt命令執行。