是时候抛弃繁重的Grunt了。Gulp是一个直观的、配置的、基于流的任务发布系统,而且它更高效。
为什么我会感兴趣呢?好问题。Gulp通过配置写代码不仅使得它编写任务简单,而且更加方便阅读和维护。
Gulp运用node.js的流,这使得它构建任务很快,因为没有磁盘文件的读写操作,如果你想了解更多关于流的知识,你可以看看这个。Gulp允许你输入源文件,然后在一系列的管道插件中处理,最后输出,不像Grunt你需要为每个插件配置输入和输出。下面就让我们通过一个sass编译的例子来看看Gulp和Grunt的差异吧。
Grunt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| sass: { dist: { options: { style: 'expanded' }, files: { 'dist/assets/css/main.css': 'src/styles/main.scss', } } },
autoprefixer: { dist: { options: { browsers: [ 'last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4' ] }, src: 'dist/assets/css/main.css', dest: 'dist/assets/css/main.css' } },
grunt.registerTask('styles', ['sass', 'autoprefixer']);
|
Grunt要求每个插件配置要相互独立、要分别为每个插件配置输入源和输出路径。如,我们在sass插件里面配置了一个输入文件,然后保存输出。接着我们需要配置Autoprefixer的输入为Sass的输出,然后再输出了一个文件。让我们来看看Gulp是怎么做的:
Gulp:
1 2 3 4 5 6
| gulp.task('sass', function() { return gulp.src('src/styles/main.scss') .pipe(sass({ style: 'compressed' })) .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4')) .pipe(gulp.dest('dist/assets/css')) });
|
在Gulp中我们只配置一次输入文件,然后依次通过Sass插件处理,再传给Autoprefixer
插件处理,然后我们得到输出文件。整个过程没有读取和写入不必要的文件,效率大大提高。
因此,你感兴趣了么?让我们从安装Gulp,创建基本的任务配置文件gulpfile
开始吧。
安装gulp
在我们开始配置任务之前,我们先要安装gulp:
这样gulp就以全局的方式安装了,你可以在任何node命令行里面调用gulp CLI
。然后我们需要在本地的某个项目里面使用gulp
。使用cd
命令进入到项目目录,运行下面的命令(先确保项目目录存在package.json
文件):
1
| npm install gulp --save-dev
|
这会把gulp安装到本地项目,并且把依赖的包写入到package.json
文件的devDependencies
里面
安装gulp插件
我们将会安装下列插件来开始我们的任务:
运行下面的命令安装这些插件:
1
| npm install gulp-ruby-sass gulp-autoprefixer gulp-minify-css gulp-jshint gulp-concat gulp-uglify gulp-imagemin gulp-notify gulp-rename gulp-livereload gulp-cache del --save-dev
|
这将会安装所有的依赖插件,并写入到package.json的devDependencies里面。所有的gulp插件列表可以在这里看到。
加载插件
我们需要创建一个gulpfile.js
,然后使用这些插件:
1 2 3 4 5 6 7 8 9 10 11 12 13
| var gulp = require('gulp'), sass = require('gulp-ruby-sass'), autoprefixer = require('gulp-autoprefixer'), minifycss = require('gulp-minify-css'), jshint = require('gulp-jshint'), uglify = require('gulp-uglify'), imagemin = require('gulp-imagemin'), rename = require('gulp-rename'), concat = require('gulp-concat'), notify = require('gulp-notify'), cache = require('gulp-cache'), livereload = require('gulp-livereload'), del = require('del');
|
我们也可以像grunt那样自动加载插件:auto load
创建任务
编译sass、加前缀、压缩
1 2 3 4 5 6 7 8 9 10
| gulp.task('styles', function() { return gulp.src('src/styles/main.scss') .pipe(sass({ style: 'expanded' })) .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4')) .pipe(gulp.dest('dist/assets/css')) .pipe(rename({suffix: '.min'})) .pipe(minifycss()) .pipe(gulp.dest('dist/assets/css')) .pipe(notify({ message: '样式任务完成' })); });
|
sass({ style: ‘expanded’ }:编译后保留原格式
1
| gulp.task('styles', function() { ... )};
|
gulp.task
API是用来创建任务的。然后通过命令gulp styles
运行这个任务。
1
| return gulp.src('src/styles/main.scss')
|
gulp.src
API用来配置输入的源文件。也可以用模式匹配,如/**/*.scss
匹配所有文件夹下面后缀为.scss
的文件作为输入。通过返回流使得它是异步的,确保在提醒任务完成的时候任务是完成了的。
1
| .pipe(sass({ style: 'expanded' }))
|
通过.pipe()
把源文件流入一个插件的管道中。然后我们可以去插件的官网看看这个插件的详细用法。
1
| .pipe(gulp.dest('dist/assets/css'));
|
gulp.dest
API是用来告知输出文件的路径的。一个任务可以有多个输出,如一个用来输出原来的版本(即源文件),一个输出处理后的版本(即输出文件)。你可以在上面的styles
任务中看到。
建议去看gulp api文档,这样会更加清楚。
js语法检查、合并和压缩任务
1 2 3 4 5 6 7 8 9 10 11
| gulp.task('scripts', function() { return gulp.src('src/scripts/**/*.js') .pipe(jshint('.jshintrc')) .pipe(jshint.reporter('default')) .pipe(concat('main.js')) .pipe(gulp.dest('dist/assets/js')) .pipe(rename({suffix: '.min'})) .pipe(uglify()) .pipe(gulp.dest('dist/assets/js')) .pipe(notify({ message: 'Scripts task complete' })); });
|
这里用的JSHin
t插件,我们使用了默认的JSHint Reporter
,可能适用于大多数人,想了解更多可以去jshint官网看
图片压缩任务
1 2 3 4 5 6
| gulp.task('images', function() { return gulp.src('src/images/**/*') .pipe(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true })) .pipe(gulp.dest('dist/assets/img')) .pipe(notify({ message: 'Images task complete' })); });
|
这里我们只用了imagemin
插件,但是可以做的更好,我们可以缓存修改过的图片,或者只对修改过的图片进行再次的压缩操作,因此我们可以使用gulp-cahce插件,因此我们需要将这行代码:
1
| .pipe(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true }))
|
改成:
1
| .pipe(cache(imagemin({ optimizationLevel: 5, progressive: true, interlaced: true })))
|
此时,只有新的图片或者改变过的图片才会被压缩。
文件清理
在再次发布之前,我们最好把目标文件的文件先清理掉,然后重新构建:
1 2 3
| gulp.task('clean', function(cb) { del(['dist/assets/css', 'dist/assets/js', 'dist/assets/img'], cb) });
|
默认任务
我们可以通过$ gulp
启动默认任务,然后在默认任务中调用其他任务:
1 2 3
| gulp.task('default', ['clean'], function() { gulp.start('styles', 'scripts', 'images'); });
|
看到gulp.task
里面的数组了吧?这里定义了任务的依赖,也就是说default
任务依赖clean
任务。在这个例子中,执行gulp.start
之前会先运行clean
任务。Gulp里面的任务同时进行,没有明确的顺序哪个先完成,所以我们要确保clean
任务执行完之后再执行gulp.start
里面的任务。
虽然不建议在执行依赖任务数组的时候使用gulp.start
,但是在这里我们没有办法确保clean
任务执行完毕后再执行其它任务,因此这里使用gulp.start
貌似是最好的选择。
Watch任务
当文件发生变化的时候,我们可能需要重新执行任务,因此我们需要配置一个监听文件变化的任务:
1 2 3 4 5 6 7 8 9 10 11 12
| gulp.task('watch', function() {
gulp.watch('src/styles/**/*.scss', ['styles']);
gulp.watch('src/scripts/**/*.js', ['scripts']);
gulp.watch('src/images/**/*', ['images']);
});
|
我们通过gulp.watch
API来监听文件的变化,然后执行相关的依赖任务。现在我们可以执行$ gulp watch
命令来执行我们的watch
任务,监听.scss
、.js
或者图片文件的变化执行相应的任务。
LiveReload任务
当我们代码修改的时候,Gulp也可以主动帮我们刷新页面,此时我们需要配置LiveReload
服务,并修改我们的watch
任务:
1 2 3 4 5 6 7 8 9
| gulp.task('watch', function() {
livereload.listen();
gulp.watch(['dist/**']).on('change', livereload.changed);
});
|
要让这个任务生效,我们还需要安装并开启浏览器LiveReload插件,我们也可以手动添加代码片段。
整合这些任务
把上面的这些任务综合起来,就构成了一个完整的gulpfile
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
var gulp = require('gulp'), sass = require('gulp-ruby-sass'), autoprefixer = require('gulp-autoprefixer'), minifycss = require('gulp-minify-css'), jshint = require('gulp-jshint'), uglify = require('gulp-uglify'), imagemin = require('gulp-imagemin'), rename = require('gulp-rename'), concat = require('gulp-concat'), notify = require('gulp-notify'), cache = require('gulp-cache'), livereload = require('gulp-livereload'), del = require('del');
gulp.task('styles', function() { return gulp.src('src/styles/main.scss') .pipe(sass({ style: 'expanded', })) .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4')) .pipe(gulp.dest('dist/styles')) .pipe(rename({ suffix: '.min' })) .pipe(minifycss()) .pipe(gulp.dest('dist/styles')) .pipe(notify({ message: 'Styles task complete' })); });
gulp.task('scripts', function() { return gulp.src('src/scripts/**/*.js') .pipe(jshint('.jshintrc')) .pipe(jshint.reporter('default')) .pipe(concat('main.js')) .pipe(gulp.dest('dist/scripts')) .pipe(rename({ suffix: '.min' })) .pipe(uglify()) .pipe(gulp.dest('dist/scripts')) .pipe(notify({ message: 'Scripts task complete' })); });
gulp.task('images', function() { return gulp.src('src/images/**/*') .pipe(cache(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true }))) .pipe(gulp.dest('dist/images')) .pipe(notify({ message: 'Images task complete' })); });
gulp.task('clean', function(cb) { del(['dist/assets/css', 'dist/assets/js', 'dist/assets/img'], cb) });
gulp.task('default', ['clean'], function() { gulp.start('styles', 'scripts', 'images'); });
gulp.task('watch', function() { gulp.watch('src/styles/**/*.scss', ['styles']); gulp.watch('src/scripts/**/*.js', ['scripts']); gulp.watch('src/images/**/*', ['images']); livereload.listen(); gulp.watch(['dist/**']).on('change', livereload.changed); });
|
如有任何问题,可以在下面评论。