使用Grunt已經有很長一段時間了,不得不感嘆其社區的壯大,各類插件層出不窮。而在這期間我也換過幾種方式來組織Gruntfile.js
,但都不是很理想,直到前段時間看到load-grunt-tasks這個插件以及More maintainable Gruntfiles這篇文章後,我就把項目中的Gruntfile.js
都按照該文章做者所述的方式從新組織了一遍。javascript
我就暫且把這種方式用本身的文字記錄一下並分享給正在使用Grunt
的同窗們吧,不過本文也不算是對《More maintainable Gruntfiles》的翻譯吶,畢竟我E文太差~html
首先介紹下load-grunt-tasks
這個插件。java
咱們通常都會把全部用到的插件以及插件的配置寫到Gruntfile.js
裏面,對於小項目來講這個文件最終或許不是很大,可是對於大項目、有不少配置或者不少自定義任務的項目來講,最後這個文件都會變得愈來愈長,維護起來就成了麻煩。好比下面這樣:node
module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), concat: { options: { separator: ';' }, dist: { src: ['src/**/*.js'], dest: 'dist/<%= pkg.name %>.js' } }, uglify: { options: { banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n' }, dist: { files: { 'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>'] } } }, qunit: { files: ['test/**/*.html'] }, jshint: { files: ['gruntfile.js', 'src/**/*.js', 'test/**/*.js'], options: { globals: { jQuery: true, console: true, module: true, document: true } } }, watch: { files: ['<%= jshint.files %>'], tasks: ['jshint', 'qunit'] } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-qunit'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.registerTask('test', ['jshint', 'qunit']); grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']); };
這是一個很標準的Gruntfile.js
,顯然也算是很簡短的了,可是看起來也有點累覺不愛。因而load-grunt-tasks
出來幫咱們解決了一部分問題。git
它會自動讀取並加載項目packge.json
文件中devDependencies
配置下以grunt-*
開頭的依賴庫。因而乎咱們就能夠用一行代碼來搞定上面代碼中不少行的loadNpmTasks
了。github
require('load-grunt-tasks')(grunt); // 就代替瞭如下所有 grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-qunit'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-concat');
load-grunt-tasks
插件替Gruntfile.js
省去了那些反覆書寫的方法調用,接下來就是將整個Gruntfile.js
變得乾淨清爽的步驟了。那就是把上面的各類config
分離出去,讓它們各自表明本身是屬於哪一個插件,而不是一口氣全寫在一塊兒。固然,還有各類用registerTask
方法定義的自定義任務,也該單獨放到相應的文件中。npm
首先,在項目根目錄下建一個名爲tasks
的目錄,在這個目錄下來編寫各類自定義任務。能夠一個任務一個 js 文件,也能夠多個簡單任務在一個 js 文件,看我的喜愛吧。而後在Gruntfile.js
中用一行代碼來載入這些自定義任務:json
grunt.loadTasks('tasks'); // 即剛剛新建目錄的名稱
而後再在這個目錄下新建一個名爲options
的子目錄(tasks/options),來存放以前說的那些config
們。爲每一類config
建一個 js 文件,並以配置項節點名做爲文件名稱,好比下面這樣:函數
tasks └── options └── concat.js └── uglify.js └── qunit.js └── jshint.js
而後在每一個文件中導出對應的配置項,拿concat.js
來講:grunt
module.exports = exports = { options: { separator: ';' }, dist: { src: ['src/**/*.js'], dest: 'dist/<%= pkg.name %>.js' } };
最後在Gruntfile.js
裏用require
將配置逐個引入便可,也能夠封裝一個函數來作這件事情。
function loadConfig(configPath) { var config = {}; glob.sync('*', { cwd: configPath }) .forEach(function(configFile) { var prop = configFile.replace(/\.js$/, ''); config[prop] = require(path.join(__dirname, configPath, configFile)); }); return config; }
再改寫Gruntfile.js
中initConfig
的調用便可。
var _ = require('lodash'); var config = { pkg: grunt.file.readJSON('package.json') }; _.extend(config, loadConfig('./tasks/options/')); grunt.initConfig(config);
因而乎在每一個項目中Gruntfile.js
幾乎一致,並且也幾乎不會再變動。Gruntfile.js
、自定義任務、任務配置項各司其職,須要變化時只需對相應文件作出調整便可。
就在前些天,又一位 GitHuber 將這個思路封裝成了一個庫:load-grunt-config,感興趣的同窗能夠看看。
最終的Gruntfile.js
能夠查看這個例子:https://github.com/heroicyang/cnodeclub/blob/master/Gruntfile.js
load-grunt-tasks: https://npmjs.org/package/load-grunt-tasks
More maintainable Gruntfiles: http://www.thomasboyt.com/2013/09/01/maintainable-grunt.html