随着项目的推进,往往会不断有新的任务需要自动化处理,gulpfile会不断“膨胀”,如果所有内容都添加到单个gulpfile文件中,可读性和可维护性都会变得很差。

gulpfile进行合理的拆分和组织,就可以增强gulpfile的可读性、可维护性和可扩展性。

需要改写的gulpfile

以下面的gulpfile为例,对其进行拆分。因为只是为了示例,所有只定义了一个gulp任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
'use strict';

var gulp = require('gulp'),
    jshint = require('gulp-jshint'),
    jsSource = 'app/js/*.js';

gulp.task('lint', function() {
  return gulp
    .src(jsSource)
    .pipe(jshint())
    .pipe(jshint.reporter('jshint-stylish'));
  });

gulp.task('watch:js', ['lint'], function() {
  gulp.watch(jsSource, ['lint']);
});

以上就是用于改写的gulpfile,下面对其进行改写,首先看一下改写后的目录结构。

目录结构

拆分后的gulpfile主要包括3部分:

  • gulpfile.js文件:包含任务的主体逻辑,以gulp-tasks中的基本任务模块为基础,构建需要的任务
  • config.json文件:包含任务中涉及到的相关配置,比如js文件的路径
  • gulp-tasks文件夹:该文件夹下的每一个文件对应一个基本任务模块,以单一功能,可重用为书写原则

以下是gulpfile拆分后的目录结构:

.
├── config.json
├── gulpfile.js
└── gulp-tasks

第一步:使用gulp-load-plugins加载gulp插件

对每一个需要使用到的gulp插件都进行手动添加,不但麻烦,而且容易出错。

使用gulp-load-plugins模块可以一次性加载所有的与gulp相关的模块,所有模块的引用都保存到一个对象中。

gulp插件在该对象中的属性名的命名方式为:去掉gulp前缀,并且把使用-分隔的各个部分采用驼峰命名法连接起来。比如:gulp-jshint在该对象中是属性名为jshintgulp-ruby-sass在该对象中的属性名为rubySass

安装插件

1
$ npm i -D gulp-load-plugins

通过gulp-load-plugins加载gulp相关插件

下面是使用gulp-load-plugins加载gulp相关插件后gulpfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
'use strict';

var gulp = require('gulp'),
    $ = require('gulp-load-plugins')(),    // 所有的gulp插件对象
    jsSource = 'app/js/*.js';

gulp.task('lint', function() {
  return gulp
    .src(jsSource)
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'));
  });

gulp.task('watch:js', ['lint'], function() {
  gulp.watch(jsSource, ['lint']);
  });

第二步:使用外部配置文件

使用外部配置文件,可以方便地对配置进行管理、修改和重用。所有与gulp相关的配置都添加到config.json文件中。

config.json文件

1
2
3
4
5
6
{
  "tasksPath": "gulp-tasks/",
  "source": {
    "js": "app/js/*.js"
  }
}

gulpfile.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
'use strict';

var gulp = require('gulp'),
    $ = require('gulp-load-plugins')(),    // 所有的gulp插件对象
    cfg = require('./config.json');    // 所有相关配置

gulp.task('lint', function() {
  return gulp
    .src(cfg.source.js)
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'));
  });

gulp.task('watch:js', ['lint'], function() {
  gulp.watch(cfg.source.js, ['lint']);
});

第三步:把基本任务定义为一个模块

因为gulpfile本身就可以看作一个node文件,所以完全可以使用CommonJS模块系统把基本任务拆分成小的模块,不但易于阅读和维护,而且还便于重用。

拆分后的lint任务:

1
2
3
4
5
6
7
8
9
10
11
12
13
// gulp-tasks/lint.js
'use strict';

// 每一个任务模块都接受3个参数
// gulp: gulp模块
// $: 所有的`gulp`插件对象,由`gulp-load-plugins`模块生成
// cfg:配置对象,即`config.json`文件的内容
module.exports = function(gulp, $, cfg) {
  return gulp
    .src(cfg.source.js)
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'));
};

第四步:在gulpfile中获取任务模块并且使用

因为对CommonJS模块系统的支持,只需要在gulpfile中使用require就可以加载并且使用相关任务模块。

但是因为加载每一个任务模块都是类似的,所有有必要把加载任务模块的操作抽象为一个函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'use strict';

var gulp = require('gulp'),
    $ = require('gulp-load-plugins')(),
    cfg = require('./config.json');

// 将获取任务模块的操作抽象为一个函数
function getTask(taskName) {
  return require(cfg.tasksPath + taskName).bind(null, gulp, $, cfg);
}

// 使用相关任务模块定义一个`gulp`任务
gulp.task('lint', getTask('lint'));

gulp.task('watch:js', ['lint'], function() {
  gulp.watch(jsSource, ['lint']);
});