本文是开发工具集系列文章之一,其他请点击这里。
1 概述
任务构建工具(task-runner)就是一些自动化组织、执行任务的工具,用来执行一些命令或利用插件处理文件,比如压缩、转换、格式化等,比较传统的工具包括gulp,grunt,还有npm自带的npm script。
如果我们选择一个合适的打包工具,比如webpack,这些打包工具会覆盖大部分任务构建工具的功能,再加上npm script,大部分场景不再需要其他构建工具了。但是这里还是会对这三种构建工具做一下介绍以作了解。
2 grunt和gulp
目前gulp的使用数量明显多于grunt,gulp是在保留grunt精华的基础上做了改进,甚至能使用后者的插件。
在gulp官网的介绍,我们基本能了解gulp在grunt基础上做了哪些事
- 用提供的node.js api使用,而不是grunt一样重配置
- 编写功能单一的任务进行组合,而不是一个任务完成多个事情,其中的插件也是专注于特定功能
- 在文件最终输出前使用内存中的流,而不是输出中间文件
下面具体介绍一下两者的用法
2.1 grunt
grunt的使用通过配置来指定,配置文件为Gruntfile.js,当用命令行调用grunt时就会读取对应配置文件,一个配置文件包含以下四部分
- wrapper函数,即导出的整个函数
- 项目和任务配置,使用
grunt.initConfig初始化一个配置.该配置对象会在后续任务中通过grunt.config访问 - 加载插件和任务,常见的任务以插件形式封装,可以使用
grunt.loadNpmTasks加载使用。 - 自定义插件和任务,可以自定义默认的任务,可以是下例中插件封装的任务,也可以是自定义任务,比如
module.exports = function(grunt) {
// A very basic default task.
grunt.registerTask('default', 'Log some stuff.', function() {
grunt.log.write('Logging some stuff...').ok();
});
};
完整的配置文件如
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
src: 'src/<%= pkg.name %>.js',
dest: 'build/<%= pkg.name %>.min.js'
}
}
});
// 加载包含 "uglify" 任务的插件。
grunt.loadNpmTasks('grunt-contrib-uglify');
// 默认被执行的任务列表。
grunt.registerTask('default', ['uglify']);
};
更多请参考官方文档
2.2 gulp
使用gulpfile.js作为配置文件,其中包含执行的task,每个task是一个异步的js函数,接收一个error first回调或返回一个流、promise、event emiter、child process or observable。
任务分private和public,前者只能在配置文件内部调用,后者可以在外调用。多个任务可以使用series() and parallel()进行组合,前者顺序执行,后者并发执行
const { series } = require('gulp');
// The `clean` function is not exported so it can be considered a private task.
// It can still be used within the `series()` composition.
function clean(cb) {
// body omitted
cb();
}
// The `build` function is exported so it is public and can be run with the `gulp` command.
// It can also be used within the `series()` composition.
function build(cb) {
// body omitted
cb();
}
exports.build = build;
exports.default = series(clean, build);
当处理一个文件时。在src() and dest()方法间使用.pipe()可以改变文件的内容,此时便可以借助插件
const { src, dest } = require('gulp');
const uglify = require('gulp-uglify');
const rename = require('gulp-rename');
exports.default = function() {
return src('src/*.js')
// The gulp-uglify plugin won't update the filename
.pipe(uglify())
// So use gulp-rename to change the extension
.pipe(rename({ extname: '.min.js' }))
.pipe(dest('output/'));
}
3. npm srcipt
前面我们熟悉了grunt和gulp的工作模式,它们存在以下问题
- 需要借助插件处理,其生态与npm script所需包相比不够完善
- 任务构建语法过于繁琐,不利于debug
再加上npm的普及,现在npm script+打包工具的组合对上述工具的优势已经十分明显。现在对npm script相关功能做一下讨论,参考官方文档。
npm script的脚本位于package.json的scripts字段。
其中的命令使用npm run 执行,对应的premyscript和postmyscript也会先后执行,比如
{
"scripts": {
"precompress": "{{ executes BEFORE the `compress` script }}",
"compress": "{{ run command to compress files }}",
"postcompress": "{{ executes AFTER `compress` script }}"
}
}
还可以使用&& 一次性执行多个命令或者互相调用
"scripts": {
...
"build:images": "npm run imagemin && npm run icons",
"build:all": "npm run build:css && npm run build:js && npm run build:images",
}
完结撒花