Gulp


流式构建工具


@vinenthou

 

微博: frontnode

QQ: 2080432723

邮箱: frontnode@126.com

开源地址: github.com/frontnode


Web开发,流程改进,最佳实践,性能优化


















你的应用不是一个大车间,而是由一系列的管道打通的





我们应该有如同使用橡胶软管的方法来连接程序——当需要通过不同的方式来操作数据的时候能够将另外的片段连接进来。这也是IO的方式.
- Doug McIlroy


最早流的概念是在UNIX里提出来的并且历经多年的实践验证证明这是一种可靠的方式。这也顺应了UNIX的设计思路,每个组件只做一件事情,并且将这件事情做好,大型的系统是由这些小的可靠的组件来组成。
你可以将一个流的输出作为另一个流的输入并且使用库来抽象地操纵流以描述高层次的流程控制。
- substack

程序员都知道流程控制


阅读substack关于流的简明概览



学习新的流程控制技术让你更加高效






为什么是流?
















在头脑中描绘一个构建系统的样子。

(它需要读入文件,修改它们并且输出新的文件)

你可能是这样想的

绝不是这样的











糟糕的情况是怎样的?


  • 一个插件做了过多的事情
    • 只是想使用javascript压缩器,需要先回答是不是要添加banner
  • 插件做了不该插件做的事情
    • 想要运行测试?装个插件吧
  • 当你想做很多事情的时候config的格式看起来就是一坨...
    • 不是按照node的方式来书写的
  • 由于不良的流程控制导致一堆头疼的临时文件和目录


你的构建系统应该助力而不是阻碍你的工作

它应该仅仅操纵文件,让其他的库来处理其他的问题

Gruntfile例子

 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: {
        // options here to override JSHint defaults
        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']);

};
  1. 代码静态检查
  2. 运行测试
  3. 合并JS
  4. 压缩文件
  5. 如果文件改动了重新执行上面的步骤

切换工具



Gulpfile 例子

var gulp = require('gulp');
var pkg = require('./package.json');
var concat = require('gulp-concat');
var minify = require('gulp-minify');
var jshint = require('gulp-jshint');
var spawn = require('child_process').spawn;

var scriptFiles = './src/**/*.js';

gulp.task('compile', function(){
  // concat all scripts, minify, and output
  gulp.src(scriptFiles)
    .pipe(concat({fileName: pkg.name+".js"})
    .pipe(minify())
    .pipe(gulp.dest('./dist/'));
});

gulp.task('test', function(){
  // lint our scripts
  gulp.src(scriptFiles).pipe(jshint());
  
  // run our tests
  spawn('npm', ['test'], {stdio: 'inherit'});
});
    
gulp.task('default', function(){
  gulp.run('test', 'compile');
  gulp.watch(scriptFiles, function(){
    gulp.run('test', 'compile');
  });
});
  1. 代码静态检查
  2. 运行测试
  3. 合并JS
  4. 压缩文件
  5. 如果文件改动了重新执行上面的步骤

有啥不一样的?


  • 用 Gulp 后你的构建文件看起来是程序而不是配置
  • 十分易于上手,核心API只有4个
  • 你可以使用nodejs或者javascript的标准库和方法来做事情
  • 单一责任原则,插件很简单并且只做一件事情——最多是个20行的方法
  • 任务以最大并发来执行
  • I/O 以你想象中的方式工作,基于流,而不是生成很多临时文件(像grunt的方法一样)

安装


添加命令行工具

npm install -g gulp 


添加项目开发依赖

cd project
npm install gulp --save-dev 

 编写代码


var gulp = require('gulp');

gulp.task('default', function () {
    console.log('welcome to gulp');
}); 

运行一把


gulp 



就是这么简单

跟grunt差不多?



Gulp 仅仅是提供了一些流和基本的任务系统

我们来看看gulp的API,只有4个

gulp.task(name, fn)



给任务起个名字。

你也可以指定一些依赖如果其他任务需要首先运行。


gulp.watch(glob, fn)




监视文件变化并且运行相应的任务


在code中可以方便的调用

gulp.src(glob)


返回可读文件流。

获取文件系统 glob (如同grunt一样) 并且开始返回匹配的文件.


其他的流会把src作为源一级一级连接

gulp.dest(folder)


返回可写文件流

使用管道串联的文件对象被保存到文件系统

插件开发说明








祝贺



你已经是一个Gulp专家啦





如何创建你自己的插件参考README文件

其他的构建工具







Questions?

Get started with gulp

By frontnode

Get started with gulp

Streaming build systems

  • 1,552