使用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