gulp plugin开发

来源:互联网 发布:cad仿真软件 编辑:程序博客网 时间:2024/06/10 19:58

前言

前端开发近两年工程化大幅飙升。随着Nodejs大放异彩,静态文件处理不再需要其他语言辅助。主要的两大工具即为基于文件的grunt,基于流的gulp。简单来说,如果需要的只是文件处理,gulp绝对首选。如果是其他依赖于文件的任务管理,例如测试(karmamocha),推荐使用grunt

gulp plugin开发依赖

就插件开发难度而言,gulp远低于grunt。如果你只关注如何处理文件,而不关注细节,那么需要依赖Nodejs Transform stream的实现。可以使用官方推荐的through2,但推荐使用through-gulp。后者是基于前者,为gulp插件编写精简优化重写而来。千万不要使用through,这个包时间久远,长时间没有维护,而且部分mock实现的功能,到nodejs 0.10.x已经原生支持。如果只是想学习如何编写gulp插件,through-gulp更适合。
through-gulp: https://github.com/bornkiller/through-gulp
through2: https://github.com/rvagg/through2.git
through: https://github.com/dominictarr/through

gulp plugin开发结构

// PLUGIN_NAME: samplevar through = require('through-gulp');function sample() {  // creating a stream through which each file will pass  var stream = through(function(file, encoding,callback) {      // do whatever necessary to process the file       if (file.isNull()) {      }      if (file.isBuffer()) {      }      if (file.isStream()) {      }      // just pipe data next, or just do nothing to process file later in flushFunction      // never forget callback to indicate that the file has been processed.      this.push(file);      callback();    },function(callback) {      // just pipe data next, just callback to indicate that the stream's over      this.push(something);      callback();    });  // returning the file stream  return stream;};// exporting the plugin module.exports = sample;

then use the plugin with gulp

var gulp = require('gulp');var sample = require('sample');gulp.task('sample', function() {    gulp.src(['source file'])        .pipe(sample())        .pipe(gulp.dest('file destiny'))});

这个sample是一个plugin的基本模板,通常的内容处理包裹与如下所示部分,所以通常关注重点也在此处。。

if (file.isBuffer()) {  //文件处理}

需要特别注意的是,如果你需要处理的不同文件之间没有任何依赖,在第一个函数函数内部处理完后,进行如下调用,即可将该文件的处理结果传递给下一个插件。这种情况下,可以缺省第二个参数flushFunction

if (file.isBuffer()) {  // 文件处理  var data = fileProcess(file);  // 传递处理后数据给下一个插件  this.push(data);   // 声明该文件处理完毕  callback();}

如果需要处理的不同文件之间存在依赖,例如文件合并,需要所有文件全部读完之后再处理,那么第一个参数transformFunction将每次传递进来的数据保存在内存中(绝对不要在这里调用this.push()方法),第二个参数flushFunction统一做处理后,再传递给下一个插件。

// transformFunctionvar fileStorage = [];if (file.isBuffer()) {  // 文件处理  var data = fileProcess(file);  // 保存传递进来的数据  fileStorage.push(data);   // 声明该文件处理完毕  callback();}
// flushFunctionfunction(callback) {  var result = '';  var final = null;  fileStorage.foreach(function(file, key) {    result += file.contents.toString();  })  final = new Buffer(result);  this.push(final);  callback();}

gulp优势浅析

  • 基于stream
    grunt基于文件的机制,导致了任务之间没有信息传递。举简单例子说明,任务流程基本上打开文件、处理文件、保存文件、关闭文件,然后执行继续向后执行任务。每一个任务都需要做重复的打开、保存、关闭操作无疑影响效率。gulp的特点在于单入口模式,文件打开、保存、关闭均一次,从内存拿数据,肯定比从硬盘拿数据快。

  • 配置项精简
    grunt的配置项繁杂算是公认的弊病,options嵌套表现尚可,扩展模式与非扩展模式,而且自带concat行为有时让人难以理解。以coffee script的编译举例

// Gruntfile.js// 包装函数module.exports = function(grunt) {    // 任务配置    grunt.initConfig({        pkg: grunt.file.readJSON('package.json'),        coffee: {            options: {                bare: true,                sourceMap: true            },            compile: {                files: {                    'storage-coffee/judge.js': ['storage-coffee-source/judge.coffee'],                    'storage-coffee/storage.js': ['storage-coffee-source/storage.coffee']                }            }        }    // 任务加载    grunt.loadNpmTasks('grunt-contrib-coffee');};
// gulpfile.jsvar gulp = require('gulp');var gutil = require('gulp-util');var coffee = require('gulp-coffee');var sourcemaps = require('gulp-sourcemaps');gulp.task('coffee', function() {  gulp.src('storage-coffee-source/*.coffee')    .pipe(sourcemaps.init())    .pipe(coffee({bare: true}).on('error', gutil.log))    .pipe(sourcemaps.write('./'))    .pipe(gulp.dest('storage-coffee'));});
  • 插件任务明确
    grunt插件基本上都是多功能,如上所示,grunt-contrib-coffee附带sourcemap功能,而gulp-coffee则只负责编译,sourcemap交由其他插件处理。私以为,功能单一化可以更好地组合使用。

后记

就插件编写的角度而言,through-gulp方法更加精炼,是为gulp插件开发而生,而不是为了node stream开发而生,所以无需理会through2晦涩的文档,之前有一个不幸的地方,在gulp插件开发的单元测试中,常用的assert-stream是基于through2的,但是不影响大局。现在基于through-gulp编写gulp插件测试的模块stream-assert-gulp,目的在于为gulp插件编写与测试降低难度。基于前两者,编写了gulp-requirejs-optimizer插件作为使用requirejs作为AMD加载器的优化工作,基本可用。

  • through-gulp : https://github.com/bornkiller/through-gulp。
    NPM
  • stream-assert-gulp : https://github.com/bornkiller/stream-assert-gulp
    NPM
  • gulp-requirejs-optimizer : https://github.com/bornkiller/gulp-requirejs
    NPM
0 0