使用 Gulp 构建工程

gulp 是什么?

如果曾做过 Linux C 相关开发,一定对于编译构建工具 Automake 有一定的了解,我们通过在工程中编写 makefile 脚本文件,实现工程代码的检查、编译以及安装等等。

而在如今前端工程化的背景下,愈来愈强调前端的工作流程,如果有一种工具,能够如 automake 一般,能够帮助我们处理检测、编译、自动发布以及文件压缩、文件Hash、等等事宜,那一定能简化不少工作,而 gulp 即是这样的一种工具。


Gulp 是一个基于 Node.js 的流式构建工具,有别与 Grunt 基于 I/O 的构建方式,Grunt 在处理过程中会产生一些中间态的临时文件,而任务会最终基于这些临时文件生成构建后的结果文件。在这个过程中 Grunt 会进行大量的 I/O 读写操作,那么如果遇到大型项目工程,Grunt 的构建处理速度将大大拖长,这也就是为什么 Gulp 渐渐取代 Grunt 的原因之一,如果想了解更多,可以试着阅读 《 gulp vs grunt 》 这篇文章。

由于 Gulp 通过代码优于配置的策略不仅使得任务易于编写,同时也易于维护和阅读。Gulp 基于的 NodeJS 的流,使用管道 Pipe 的概念,这一级的输出作为下一级的输入,中间无需在硬盘上写入任何临时文件和目录,让任务构建的更加迅速。

Gulp 的基本安装 :

这里我默认您已经安装了 Node.js 以及 NPM 包管理工具,首先需要全局安装 Gulp 工具:

$ npm install gulp -g

然后,需要在已有的项目中安装 gulp 的依赖包(前提是项目中已存在 package.json 文件):

$ npm init    #如果项目中没有 package.json 文件,需要执行此命令生成,有则忽略;
$ npm install gulp --save-dev    #安装 gulp 依赖包

一切顺利,将会发现 package.json 文件中的 devDependencies 项里多了一个 gulp 子项,且 node_modules 中也多了一个 gulp 的依赖包;

Gulp 插件的安装 :

要使用 Gulp 中的功能,必须依赖于 Gulp 的插件,在 Gulp 中每个插件完成一个具体的功能任务,而实际的构建工作往往是多个任务的流程,所以就要涉及到多个插件的安装,那么具体要用到哪些插件呢?这里我大概列出了常用的几项,仅供参考。

  • Sass compile (gulp-ruby-sass) # css 预处理器编译
  • Autoprefixer (gulp-autoprefixer) # css 浏览器兼容前缀处理
  • Minify CSS with cssnano (gulp-cssnano) # css 文本压缩
  • JSHint (gulp-jshint) # JS 代码检测
  • Concatenation (gulp-concat) # 代码文本合并
  • Uglify (gulp-uglify) # 代码文本压缩
  • Compress images (gulp-imagemin) # 图片资源压缩
  • LiveReload (gulp-livereload) # 文件变动页面重载
  • Caching of images so only changed images are compressed (gulp-cache) # 图片资源缓存
  • Notify of changes (gulp-notify) # 任务完成通知提示
  • Clean files for a clean build (del) # 清理构建目录及文件

安装方式与安装 Gulp 依赖包命令一致:

$ npm install [package-name] --save-dev

Gulp 任务文件的配置 :

这里我直接使用本人 Github 上的一个聊天室项目 node_chat 来进行讲解。

// 加载插件
var del = require('del'),
    gulp = require('gulp'),
    cache = require('gulp-cache'),
    jshint = require('gulp-jshint'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    rename = require('gulp-rename'),
    notify = require('gulp-notify'),
    cssnano = require('gulp-cssnano'),
    imagemin = require('gulp-imagemin'),
    livereload = require('gulp-livereload'),
    autoprefixer = require('gulp-autoprefixer');

// 设置源路径
var srcPaths = {
    scripts: ['./public/javascripts/*.js'],
    images: './public/images/*',
    styles: './public/stylesheets/*.css'
};

// 设置目标路径
var destPaths = {
    all: './build/**',
    scripts: './build/script',
    images: './build/image',
    styles: './build/style'
};

// 任务:脚本代码验证
gulp.task('analysis', function() {
    return gulp.src(srcPaths.scripts)
        .pipe(jshint())
        .pipe(jshint.reporter('default'))
        .pipe(notify({message: 'Analysis task complete.'}));
});

// 任务1. 脚本合并与压缩
gulp.task('scripts', ['analysis'], function() {
    return gulp.src(srcPaths.scripts)
        .pipe(concat('main.js'))
        .pipe(gulp.dest(destPaths.scripts))
        .pipe(rename({suffix: '.min'}))
        .pipe(uglify())
        .pipe(gulp.dest(destPaths.scripts))
        .pipe(notify({message: 'Scripts task complete.'}));
});

// 任务2. 资源图片压缩
gulp.task('images', function() {
    return gulp.src(srcPaths.images)
        // 压缩 imagemin 并缓存 cache 图片
        .pipe(cache(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true })))
        .pipe(gulp.dest(destPaths.images))
        .pipe(notify({message: 'Images task complete.'}));
});

// 任务3. 样式表的压缩
gulp.task('styles', function() {
    return gulp.src(srcPaths.styles)
        .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
        .pipe(gulp.dest(destPaths.styles))
        .pipe(rename({suffix: '.min'}))
        .pipe(cssnano())
        .pipe(gulp.dest(destPaths.styles))
        .pipe(notify({message: 'Styles task complete.'}));
});

// 任务:清理构建目录
gulp.task('clean', function(cb) {
    // 清空 build 目录
    return del([destPaths.scripts, destPaths.images, destPaths.styles], cb);
});

// 默认任务
gulp.task('default', ['clean'], function() {
    gulp.start('scripts', 'images', 'styles');
});

// 任务:监听文件变动
gulp.task('watch', function() {
    // 监听文件变动
    gulp.watch(srcPaths.scripts, ['scripts']);
    gulp.watch(srcPaths.images, ['images']);
    gulp.watch(srcPaths.styles, ['styles']);
    // 创建 livereload 监听服务
    livereload.listen();
    // 若有改变自动重载刷新
    gulp.watch([destPaths.all]).on('change', livereload.changed);
});