前端打包構建工具grunt快速入門(大篇幅完整版)


打包的目的和意義就不用敘述了直接上干貨

http://www.gruntjs.net/getting-started里面的教程也太簡單了,需要下一番功夫去研究才行。本文將grunt打包的常用方法都用實例描述,更加清晰易懂。

 

1.    第一個簡單的grunt打包


 1)需要安裝nodejs:http://www.cnblogs.com/chuaWeb/p/nodejs-npm.html

  本人的nodejs工程目錄為F:\chuaNodejs(后續所有相對路徑都是相對於這個目錄)

2)命令行到nodejs目錄(需要系統管理員權限,不然后續過程中會報錯)執行npm install -g grunt-cli

3)在nodejs工程目錄下建一個package.json,內容為

{
  "name": "my-first-grunt",
  "file": "jquery",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.5",
    "grunt-contrib-jshint": "~0.10.0",
    "grunt-contrib-nodeunit": "~0.4.1",
    "grunt-contrib-uglify": "~0.5.0"
  }
}

  其中file屬性在Gruntfile.js中要用到的屬性,打包源名稱

  然后將devDependencies下面的包給下載下來,比如下載grunt: npm install grunt --save-dev 其他包下載方式一樣

  需要注意的是package.json中的數據必須是嚴格的json數據格式(連添加注釋都是不可以的)。

4) 在nodejs工程目錄下建一個Gruntfile.js,內容為

 1 module.exports = function (grunt) {
 2   // 項目配置
 3   grunt.initConfig({
 4     pkg: grunt.file.readJSON('package.json'),//獲取解析package.json將內容保存在pkg中
 5     uglify: {
 6       options: {
 7         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
 8       },
 9       build: {
10         src: 'src/<%=pkg.file %>.js',
11         dest: 'dest/<%= pkg.file %>.min.js'
12       }
13     }
14   });
15   // 加載提供"uglify"任務的插件
16   grunt.loadNpmTasks('grunt-contrib-uglify');
17   // 默認任務
18   grunt.registerTask('default', ['uglify']);
19 }

  里面pkg讀取package.json文件,然后可以訪問其內容中的屬性,如pkg.file。build屬性src是待壓縮的文件,dest是壓縮重定向到該文件。

  所以現在我要建立一個src目錄,目錄下面保存了一個叫做jquery.js的文件

5)命令行運行:grunt

  輸出

Running “uglify:build” (uglify) task
File dest/jquery.min.js created: 277.14 kB ->93.35 kB
>> 1 file created. 
Done.

  創建了dest/jquery.min.js

  

  注意grunt命令和grunt uglify等價。當然也可以帶上任務名稱default:grunt default能等到同樣結果。

6)總結:

  grunt.initConfig:

  為當前項目初始化一個配置對象,其中傳入的 configObject 參數可以用在后續的task中,可以通過grunt.config 方法訪問。幾乎每個項目的 Gruntfile 都會調用此方法。

  注意,任何 <% %> 模板字符串只會在取到配置數據后才被處理。

  不同的插件有各自的參數,比如例子中的uglify插件用到的參數有options和build。詳細信息需要參考各個插件。

  initConfig詳情參考:http://www.gruntjs.net/api/grunt.config#grunt.config.init

 

  grunt.loadNpmTasks:

  grunt打包主要是用到各種插件,比如上面的壓縮用的插件uglify。加載插件需要使用該方法。

  從指定的 Grunt 插件中加載任務。此插件必須通過npm安裝到本地,並且是參照 Gruntfile.js 文件的相對路徑。

  詳情參考:http://www.gruntjs.net/api/grunt.task#grunt.task.loadnpmtasks

 

  grunt.registerTask:

  注冊 "別名任務" 或 任務函數。此方法支持以下兩種類型:

  別名任務(如果指定了一個任務列表,那么,新注冊的任務將會是這一個或多個任務的別名(alias)。當此"別名任務"執行時,taskList中的所有任務都將按指定的順序依次執行。taskList 參數必須是一個任務數組。):grunt.task.registerTask(taskName, taskList)

  上面的例子就是別名任務。定義一個"default" 任務,當執行 Grunt 且不通過參數指定任務時,第二個參數中的任務將依序執行

  任務函數(如果傳入description和taskFunction,每當任務運行時,指定的函數(taskFunction)都會被執行。此外,當執行 grunt --help時,前面指定的描述(description)就會顯示出來。特定任務的屬性和方法在任務函數內部通過this對象的屬性即可訪問。如果任務函數返回false表示任務失敗。):grunt.task.registerTask(taskName, description, taskFunction)

  下一個例子我們就試一下這個任務函數,現在剛才例子每一個步驟目的就清晰了。

  詳情參考:http://www.gruntjs.net/api/grunt.task#grunt.task.registertask

 

2. 使用任務函數方式實現剛才的那個打包。


  其他的東西都沒有變,Gruntfile.js變成了

 1 module.exports = function (grunt) {
 2   // 加載提供"uglify"任務的插件
 3   grunt.loadNpmTasks('grunt-contrib-uglify');
 4   // 任務函數
 5   grunt.registerTask('build', 'uglify 使用 任務函數版', function () {
 6     //任務列表
 7     var tasks = ['uglify'];
 8     // 項目配置
 9     grunt.initConfig({
10       pkg: grunt.file.readJSON('package.json'),//獲取解析package.json將內容保存在pkg中
11     });
12     var uglifyTask = {
13       options: {
14         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
15       },
16       build: {
17         src: 'src/<%=pkg.file %>.js',
18         dest: 'dest/<%= pkg.file %>.min.js'
19       }
20     }
21     //將一個或多個任務放入隊列中
22     grunt.task.run(tasks);
23     //給當前項目的 Grunt 配置中的uglify屬性設置一個值。
24     grunt.config.set("uglify", uglifyTask);
25   });
26 }

  然后去命令行運行: grunt bulid

  和第一個不同的是運行命令必須帶上了任務名稱build。

  注意前面提到的任何 <% %> 模板字符串只會在取到配置數據后才被處理。

 

3. 合並壓縮


  有些時候為了減少請求需要合並多個文件,且需要壓縮。使用uglify即可做到這一點。

  Gruntfile.js代碼

 1 module.exports = function (grunt) {
 2   // 項目配置
 3   grunt.initConfig({
 4     pkg: grunt.file.readJSON('package.json'),//獲取解析package.json將內容保存在pkg中
 5     uglify: {
 6       options: {
 7         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',//壓縮目標文件頭部注釋
 8         mangle: false//變量和函數名稱不壓縮
 9       },
10       my_target: {//該對象名稱隨意
11         files: {
12           'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
13         }
14       }
15     }
16   });
17   // 加載提供"uglify"任務的插件
18   grunt.loadNpmTasks('grunt-contrib-uglify');
19   // 默認任務
20   grunt.registerTask('default', ['uglify']);
21 }

  文件壓縮的順序按照files中定義的數組的順序壓縮。我們可以通過options.mangle來設置變量和函數名稱是否壓縮。還可以有下面的用法

1 options: {
2   banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',//壓縮目標文件頭部注釋
3   mangle: {
4     except: ["jQuery"]//不壓縮的關鍵字列表
5   }
6 }

  最終jquery.js和router.js合並壓縮成libs.min.js

  詳情參考:https://www.npmjs.com/package/grunt-contrib-uglify

 

4. 合並壓縮require配置的文件。


  首先需要下載grunt-contrib-requirejs插件:npm install grunt-contrib-requirejs --save-dev

  比如我們的執行文件main.js使用的是require來模塊化加載,代碼如下

 1 require.config({
 2   baseUrl: "",
 3   paths: {
 4     "jquery": "src/jquery",
 5     "bootstrap": "src/bootstrap.min",
 6     "validator": "src/bootstrapValidator.min"
 7   },
 8   shim: {
 9     "bootstrap":["jquery"],
10     "beyond": ["bootstrap"],
11     "validator": ["bootstrap"]
12   }
13 });
14 requirejs(['validator'], function (v) {
15   //代碼
16 });

  我們希望jquery/bootstrap/validator幾個文件合並成一個,避免多次請求。

  我們新建一個grunt配置文件gruntCfg.json將main.js的require文件配置代碼段拷貝到這個配置文件。並寫入輸入輸出目標。源碼如下

 1 {
 2   "requirejs": {
 3     "main": {
 4       "options": {
 5         "baseUrl": "",
 6         "paths": {
 7           "jquery": "src/jquery",
 8           "bootstrap": "src/bootstrap.min",
 9           "validator": "src/bootstrapValidator.min"
10         },
11         "shim": {
12           "bootstrap":["jquery"],
13           "validator": ["bootstrap"]
14         },
15         "include":["validator","jquery","bootstrap"],
16         "out":"dest/libs.js"
17       }
18     }
19   }
20 }

  上面include中我打亂了順序,為了測試壓縮順序我在三個庫的前面都添加了console.log(“我是” + 模塊名稱)

  修改Gruntfile.js

 1 module.exports = function (grunt) {
 2   grunt.loadNpmTasks('grunt-contrib-requirejs');
 3   //為了介紹自定義任務搞了一個這個
 4   grunt.registerTask('build', 'require', function () {
 5 
 6     //設置requireJs的信息
 7     var taskCfg = grunt.file.readJSON('gruntCfg.json');
 8     var requireTask = taskCfg.requirejs;
 9 
10     //添加人任務列表
11     grunt.task.run(['requirejs']);
12     grunt.config.set("requirejs", requireTask);
13   });
14 }

  好了現在看一下相關文件的文件結構如下

  

  執行build任務:grunt build

  文件夾dest下多了一個libs.js文件

  

  打開來看

  

  第一行代碼就有我剛才添加的console。繼續找我添加的標志的話發現壓縮順序是:jQuery->bootstrap->bootstrapValidator。和我們的shim依賴順序一致。說明合並壓縮的順序沒有問題。

  更多詳情請查看:https://www.npmjs.com/package/grunt-contrib-requirejs

 

5. 多任務


  我們先看一下使用別名任務來執行多個任務的情況,Gruntfile.js源碼如下

 1 module.exports = function (grunt) {
 2   // 項目配置
 3   grunt.initConfig({
 4     pkg: grunt.file.readJSON('package.json'),//獲取解析package.json將內容保存在pkg中
 5     uglify: {
 6       options: {
 7         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
 8       },
 9       build: {
10         src: 'src/<%=pkg.file %>.js',
11         dest: 'dest/<%= pkg.file %>.min.js'
12       },
13       my_target1: {
14         files: {
15           'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
16         }
17       },
18       my_target2: {
19         files: {
20           'dest/libs.min2.js': ['src/jquery.js', 'src/router.js']
21         }
22       }
23     },
24     requirejs: {
25       "main": {
26         "options": {
27           "baseUrl": "",
28           "paths": {
29             "jquery": "src/jquery",
30             "bootstrap": "src/bootstrap.min",
31             "validator": "src/bootstrapValidator.min"
32           },
33           "shim": {
34             "bootstrap":["jquery"],
35             "validator": ["bootstrap"]
36           },
37           "include":["validator","jquery","bootstrap"],
38           "out":"dest/libs.js"
39         }
40       },
41       "main2": {
42         "options": {
43           "baseUrl": "",
44           "paths": {
45             "jquery": "src/jquery",
46             "bootstrap": "src/bootstrap.min",
47             "validator": "src/bootstrapValidator.min"
48           },
49           "shim": {
50             "bootstrap":["jquery"],
51             "validator": ["bootstrap"]
52           },
53           "include":["validator","jquery","bootstrap"],
54           "out":"dest/libs2.js"
55         }
56       }
57     }
58 
59   });
60   // 加載提供"uglify"任務的插件
61   grunt.loadNpmTasks('grunt-contrib-uglify');
62   grunt.loadNpmTasks('grunt-contrib-requirejs');
63   // 默認任務
64   grunt.registerTask('default', ['uglify',"requirejs"]);
65 }

  執行:grunt

  dest文件夾下多出了5個文件

  

  源碼解析是:任務列表有兩個任務'uglify'和"requirejs",'uglify'有三個子任務:build/ my_target1/ my_target2, "requirejs"有兩個子任務main/main2。最終這五個子任務完成后生成的結果就是dest下多出的5個文件。

 

  還可以使用任務函數方式注冊多個任務。Gruntfile.js源碼如下

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     log: {
 4       l1: [1,2,3],
 5       l2: 'hello world',
 6       l3: false,
 7       l4: {name: "chua"},
 8       l5: 1,
 9       //這個是不行的l6: undefined,
10       //這個是不行的l7: null
11       l8: function(){alert("test")}
12     }
13   });
14 
15   grunt.registerMultiTask('log','log stuff.', function(){
16       grunt.log.writeln(this.target + ': ' + this.data);
17   });
18 }

  執行:grunt log

  

 

  我們使用自定義方式實現先前的多任務Gruntfile.js源碼如下

 1 module.exports = function (grunt) {
 2   // 項目配置
 3   grunt.initConfig({
 4     pkg: grunt.file.readJSON('package.json'),//獲取解析package.json將內容保存在pkg中
 5     log: {
 6       uglify: {
 7         options: {
 8           banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
 9         },
10         build: {
11           src: 'src/<%=pkg.file %>.js',
12           dest: 'dest/<%= pkg.file %>.min.js'
13         },
14         my_target1: {
15           files: {
16             'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
17           }
18         },
19         my_target2: {
20           files: {
21             'dest/libs.min2.js': ['src/jquery.js', 'src/router.js']
22           }
23         }
24       },
25       requirejs: {
26         "main": {
27           "options": {
28             "baseUrl": "",
29             "paths": {
30               "jquery": "src/jquery",
31               "bootstrap": "src/bootstrap.min",
32               "validator": "src/bootstrapValidator.min"
33             },
34             "shim": {
35               "bootstrap":["jquery"],
36               "validator": ["bootstrap"]
37             },
38             "include":["validator","jquery","bootstrap"],
39             "out":"dest/libs.js"
40           }
41         },
42         "main2": {
43           "options": {
44             "baseUrl": "",
45             "paths": {
46               "jquery": "src/jquery",
47               "bootstrap": "src/bootstrap.min",
48               "validator": "src/bootstrapValidator.min"
49             },
50             "shim": {
51               "bootstrap":["jquery"],
52               "validator": ["bootstrap"]
53             },
54             "include":["validator","jquery","bootstrap"],
55             "out":"dest/libs2.js"
56           }
57         }
58       }
59     }
60   });
61   // 加載提供"uglify"任務的插件
62   grunt.loadNpmTasks('grunt-contrib-uglify');
63   grunt.loadNpmTasks('grunt-contrib-requirejs');
64   
65   grunt.registerMultiTask('log','log stuff.', function(){
66     if(this.target == "uglify"){
67       //添加人任務列表
68       grunt.task.run(['uglify']);
69       grunt.config.set("uglify", this.data);
70     }else if(this.target == "requirejs"){
71       //添加人任務列表
72       grunt.task.run(['requirejs']);
73       grunt.config.set("requirejs", this.data);
74     }
75   });
76 }

  執行:grunt log

  照樣得到先前的結果

  

  說到底和先前的別名任務沒有什么不同。

 

6. 壓縮整個文件夾下的js文件


  壓縮src下的所有js文件,Gruntfile.js源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     uglify: {
 4       my_target: {
 5         files: [{
 6           expand: true,
 7           cwd: 'src',
 8           src: '**/*.js',
 9           dest: 'dest'
10         }]
11       }
12     }
13   });
14   grunt.loadNpmTasks('grunt-contrib-uglify');
15   grunt.registerTask('default', ['uglify']);
16 }

  源碼文件結構(注意src/router下面還有一個js文件)

  

  執行:grunt

  目標文件結構

  

  所以這個方法還是比較方便的,他會遍歷源文件夾下的所有文件(包括子文件夾)然后壓縮。

 

  剛才上面的方式沒有拷貝src文件夾,下面這種方式拷貝了src文件夾

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     uglify: {
 4       my_target: {
 5         files: [{
 6           expand: true,
 7           //cwd: 'src',
 8           src: 'src/**/*.js',
 9           dest: 'dest'
10         }]
11       }
12     }
13   });
14   grunt.loadNpmTasks('grunt-contrib-uglify');
15   grunt.registerTask('default', ['uglify']);
16 }

  執行:grunt

  目標文件結構變成

  

  src下所有的js都被壓縮並保持原來的目錄結構。

 

7. grunt-contrib-requirejs插件的更詳細使用


  我們用實例來說明。現在我們的文件結構是這樣子的

  

  main.js是我們使用require的真實配置文件,源碼如下

 1 require.config({
 2   baseUrl: "",
 3   paths: {
 4     "jquery": "src/jquery",
 5     "bootstrap": "src/bootstrap.min",
 6     "validator": "src/bootstrapValidator.min"
 7   },
 8   shim: {
 9     "bootstrap":["jquery"],
10     "beyond": ["bootstrap"],
11     "validator": ["bootstrap"]
12   }
13 });
14 requirejs(['validator'], function (v) {
15   //代碼
16 });

  Gruntfile.js的源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     "requirejs": {
 4       "main": {
 5         "options": {
 6           "baseUrl": ".",
 7           "mainConfigFile": "main.js",//指定配置文件
 8           "name": "test",//會將對應的文件壓縮到main.js依賴的文件的前面壓縮。但是會在main.js非依賴文件后面壓縮(比如router.js)
 9           "include":["jquery","bootstrap","validator","src/router/router.js"],//要壓縮在一起的文件(會包括name對應的文件)
10           "out":"dest/libs.js"
11         }
12       }
13     }
14   });
15   grunt.loadNpmTasks('grunt-contrib-requirejs');
16   grunt.registerTask('default', ['requirejs']);
17 }

  需要說明的是name指定的文件內容會在main.js配置的依賴文件壓縮之前壓縮,但是如果include中還包含其他非main.js依賴的文件,則會在main.js非依賴文件后面壓縮。

  我們的test.js源碼為

1 console.log("這是我隨便測試用的一個js");

  然后我們執行:grunt

  結果在dest下生成一個libs.js壓縮文件

  

  並且這個文件里面包含的壓縮文件的順序是:router.js->test.js->jquery.js-> bootstrap.min.js-> bootstrapValidator.min.js。

  所以說配置include中文件會依序壓縮到libs.js,但是main.js依賴的文件會放在最后(依賴會逐層往上查找依賴),而name指定的文件會在非依賴文件之后依賴文件之前壓縮。

 

  require模板文件打包

  模板文件使用到require工程上的text.js文件,路徑:http://github.com/requirejs/text

  我們這里建立一個模板文件test.html

1 <!DOCTYPE html>
2 <html>
3 <head>
4   <title>test</title>
5 </head>
6 <body>
7 </body>
8 </html>

  實際上現在test.html沒有用到任何模板相關的運用,我們只是做打包例子,所以不管其他,我們只需要知道模板文件一般是html文件即可

  現在工程的文件結構是

  

  Gruntfile.js的源碼為

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     "requirejs": {
 4       "main": {
 5         "options": {
 6           baseUrl: ".",
 7           paths: {
 8             "jquery": "src/jquery",
 9             "bootstrap": "src/bootstrap.min",
10             "validator": "src/bootstrapValidator.min",
11             "text": "text"//引入requirejs項目下解析模板引擎
12           },
13           shim: {
14             "bootstrap":["jquery"],
15             "beyond": ["bootstrap"],
16             "validator": ["bootstrap"]
17           },
18           "include":["jquery","bootstrap","validator","text!test.html"],          "out":"dest/libs.js"
19         }
20       }
21     }
22   });
23   grunt.loadNpmTasks('grunt-contrib-requirejs');
24   grunt.registerTask('default', ['requirejs']);
25 }

  執行命令行:grunt

  dest文件下多了一個libs.js,查看其中是否有模板文件test.html中的內容

  

  說明模板被一同壓縮進去了。關鍵是"text!test.html"這句話。test會將模板test.html解析成js腳本形式。

 

8.  cssmin打包樣式文件


  需要用npm下載cssmin插件:npm install grunt-contrib-cssmin --save-dev

  Gruntfile.js文件源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     cssmin: {
 4       compress: {
 5         files: {
 6           'dest/t.min.css': ["src/t1.css","src/t2.css"]
 7         }
 8       }
 9     }
10   });
11 
12   grunt.loadNpmTasks('grunt-contrib-cssmin');
13 
14 }

  命令行執行:grunt cssmin

  兩個css文件壓縮打包到dest/t.min.css

 

9. htmlmin打包html文件


  需要用npm下載cssmin插件:npm install grunt-contrib-htmlmin --save-dev

  Gruntfile.js源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({ 
 3     htmlmin: {
 4       main: {
 5         options:{
 6           removeComments: true,
 7           collapseWhitespace: true
 8         },
 9         files:{
10           "dest/test.html": "test.html"
11         }
12       }
13     }
14   });
15 
16   grunt.loadNpmTasks('grunt-contrib-htmlmin');
17   grunt.registerTask("default",["htmlmin"]);
18 }

  執行命令:grunt

  test.html壓縮到dest/test.html

  

10. copy拷貝文件


  需要下載copy插件npm install grunt-contrib-copy --save-dev

  將src文件夾(包括內容和子文件內容)拷貝到dest目錄下,Gruntfile.js源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({ 
 3     copy: {
 4       main: {
 5         expand: true,
 6         src: 'src/**',
 7         dest: 'dest/'
 8       }
 9     }
10   });
11 
12   grunt.loadNpmTasks('grunt-contrib-copy');
13   grunt.registerTask("default",["copy"]);
14 }

  運行:grunt

  src被完美的拷貝到dest下

   

 

  只拷貝src的第一層子文件,Gruntfile.js源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({ 
 3     copy: {
 4       main: {
 5         expand: true,
 6         src: 'src/*',
 7         dest: 'dest/'
 8       }
 9     }
10   });
11 
12   grunt.loadNpmTasks('grunt-contrib-copy');
13   grunt.registerTask("default",["copy"]);
14 }

  運行結果

  

  這個時候router是空文件夾。

  所以這里我們需要明白路徑中“*”只表示當前這一層,“**”表示需要遞歸子文件夾   

 

  如果只是拷貝src中的內容而不用src包裹則需要cwd屬性

 1 module.exports = function (grunt) {
 2   grunt.initConfig({ 
 3     copy: {
 4       main: {
 5         expand: true,
 6         cwd: "src/",
 7         src: '*',//也可以是數組形式["*"],可以過濾多種類型
 8         dest: 'dest/'
 9       }
10     }
11   });
12 
13   grunt.loadNpmTasks('grunt-contrib-copy');
14   grunt.registerTask("default",["copy"]);
15 }

  執行結果是

  

  注意下面這種寫法會報錯

module.exports = function (grunt) {
  grunt.initConfig({ 
    copy: {
      main: {
        expand: true,
        cwd: "src",
        src: '/*',//會報錯,不能以/開頭,會被認為是絕對路徑
        dest: 'dest/'
      }
    }
  });

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

 

  拷貝src文件夾下指定類型的文件,Gruntfile.js源碼

module.exports = function (grunt) {
  grunt.initConfig({ 
    copy: {
      main: {
        expand: true,
        src: 'src/*.js',
        dest: 'dest/'
      }
    }
  });

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

  執行:grunt

  結果src的js文件隨src文件夾被拷貝

  

 

  遞歸拷貝src文件夾下所有子文件夾中的js文件

 1 module.exports = function (grunt) {
 2   grunt.initConfig({ 
 3     copy: {
 4       main: {
 5         expand: true,
 6         src: 'src/**/*.js',
 7         dest: 'dest/'
 8       }
 9     }
10   });
11 
12   grunt.loadNpmTasks('grunt-contrib-copy');
13   grunt.registerTask("default",["copy"]);
14 }

  執行結果

  

 

  將所有指定類型的文件提取到同一層,Gruntfile.js源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({ 
 3     copy: {
 4       main: {
 5         flatten: true,//所有文件提取到dest下
 6         expand: true,
 7         src: 'src/**/**.js',
 8         dest: 'dest/'
 9       }
10     }
11   });
12 
13   grunt.loadNpmTasks('grunt-contrib-copy');
14   grunt.registerTask("default",["copy"]);
15 }

  執行結果

  

  我們發現router/router.js被提取到了目標目錄下,這也是flatten的作用

 

11. 使用contrib-watch和newer實時監聽文件更改


  這里需要用到兩個插件,下載這兩個插件

  grunt-contrib-watch —— 作用是實現我們一開始需求的“自動化”!它會監聽需要處理的文件的變動,一旦有變動就會自動執行相應處理。但是它有一個問題,就是每當監聽到一處變動時,就會大費周章地把所有被監聽的文件都處理一遍;

  grunt-newer —— 作用是處理上方watch的毛病,讓watch在監聽到某個文件變動時,僅僅對變動的文件進行事務處理。

  我們以合並壓縮為例,Gruntfile.js源碼

 1 module.exports = function (grunt) {
 2   // 項目配置
 3   grunt.initConfig({
 4     uglify: {
 5       my_target: {//該對象名稱隨意
 6         files: {
 7           'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
 8         }
 9       }
10     },
11     watch: {
12       watchJs: {
13         files: ["src/**/*.js"],
14         tasks: ["newer:uglify"]//一旦監聽到files中文件修改,立馬觸發uglify任務
15       }
16     }
17   });
18   // 加載提供"uglify"任務的插件
19   grunt.loadNpmTasks('grunt-contrib-uglify');
20   grunt.loadNpmTasks('grunt-contrib-watch');
21   grunt.loadNpmTasks('grunt-newer');
22   // 默認任務
23   grunt.registerTask('default', ['uglify',"watch"]);
24 }

  上面watch任務有一個子任務watchJs監聽js的變動,一旦監聽到files更改就觸發uglify任務。

  

12. 使用autoprefixer自動為CSS規則添加最合適的前綴兼容瀏覽器


  Autoprefixer解析CSS文件並且添加瀏覽器前綴到CSS規則里,使用Can I Use的數據來決定哪些前綴是需要的。

  需要下載grunt-autoprefixer插件

  Gruntfile.js源碼實例

 1 module.exports = function (grunt) {
 2   // 項目配置
 3   grunt.initConfig({
 4     autoprefixer : {
 5       my_target: {//該對象名稱隨意
 6         expand:true,
 7         src: "src/**/*.css",
 8         dest: "dest/"
 9       }
10     },
11     watch: {
12       watchJs: {
13         files: ["src/**/*.css"],
14         tasks: ["newer:autoprefixer"]//一旦監聽到files中文件修改,立馬觸發任務
15       }
16     }
17   });
18   // 加載提供"uglify"任務的插件
19   grunt.loadNpmTasks('grunt-autoprefixer');
20   grunt.loadNpmTasks('grunt-contrib-watch');
21   grunt.loadNpmTasks('grunt-newer');
22   // 默認任務
23   grunt.registerTask('default', ['newer:autoprefixer',"watch"]);
24 }

  這樣監聽了所有css更改,每次更改都會先添加瀏覽器兼容前綴。我們可以放心的在樣式文件中按照最新的W3C規范來正常書寫CSS而不需要瀏覽器前綴。

 

 

13. 總結


  總的來說grunt壓縮打包都是基於插件,各種插件的作用可以查看官網文檔。

  在運行任務函數指定的任務的時候可以通過冒號分割來傳遞參數。比如下面的例子

module.exports = function (grunt) {
  //為了介紹自定義任務搞了一個這個
  grunt.registerTask('test', '任務函數實例', function (arg1, arg2) {
    if (arguments.length === 0) {
      grunt.log.writeln(this.name + " 沒有參數");
    } else {
      var join = Array.prototype.join;
      grunt.log.writeln(this.name + " 的參數有" + join.call(arguments,","));
    }
  });
}

  執行:grunt test

  打印:

Runing “test” task
test 沒有參數

  執行:grunt test:1

  打印:

Runing “test:1” (test) task
test 的參數有1

  執行:grunt test:1:2

  打印:

Runing “test:1:2” (test) task
test 的參數有1,2

  正常來說我們的html/css/js文件都是用不同的文件夾保存的,所以我們可以分成三種任務來處理。這些任務都可以配置在一起,最后一次性打包,這部分根據各自實際項目情況來處理。

  ok,如果你從頭到尾看完並把上面的實例執行,那么grunt的基本功能就沒有問題了。更多的需要看具體的插件使用了。

  

  碼字不容易,求推薦。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM