Gulp,新一代流行的任务自动管理工具
#Gulp,新一代流行的任务自动管理工具
Gulp与Grunt一样,也是一个自动任务运行器。它充分借鉴了Unix操作系统的管道(pipe)思想,很多人认为,在操作上,它要比Grunt简单。
##安装
Gulp需要全局安装,然后再在项目的开发目录中安装为本地模块。先进入项目目录,运行下面的命令。
npm install -g gulp
// 将gulp安装到项目本地
npm install --save-dev gulp
// 安装插件
npm install --save-dev gulp-uglify
npm install gulp-jshint gulp-sass gulp-concat gulp-uglify gulp-rename --save-dev
##gulpfile.js
项目根目录中的gulpfile.js,是Gulp的配置文件。
var gulp = require('gulp');
gulp.task('default', function() {
});
下面就是一个典型的gulpfile.js文件。
var gulp = require('gulp'),
uglify = require('gulp-uglify');
gulp.task('minify', function() {
gulp.src('js/app.js')
.pipe(uglify())
.pipe(gulp.dest('build'))
});
gulp模块的task方法指定任务。task方法有两个参数,第一个是任务名,第二个是任务函数。
在任务函数中:
使用gulp模块的src方法,指定所要处理的文件,然后使用pipe方法,将上一步的输出转为当前的输入,进行链式处理。
从上面的例子中可以看到,gulp充分使用了“管道”思想,就是一个数据流(stream):src方法读入文件产生数据流,dest方法将数据流写入文件,中间是一些中间步骤,每一步都对数据流进行一些处理。
gulp.src('js/app.js'):指定所要处理的文件 pipe():将上一步的输出转为当前的输入,进行链式处理。 uglify():压缩源码 gulp.dest('build'):将上一步的输出写入本地文件,这里是build.js(代码中省略了后缀名js)。
// 引入 gulp
var gulp = require('gulp');
// 引入组件
var jshint = require('gulp-jshint');
var sass = require('gulp-sass');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
// 检查脚本:Link任务会检查js/目录下得js文件有没有报错或警告。
gulp.task('lint', function() {
gulp.src('./js/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'));
});
// 编译Sass:Sass任务会编译scss/目录下的scss文件,并把编译完成的css文件保存到/css目录中。
gulp.task('sass', function() {
gulp.src('./scss/*.scss')
.pipe(sass())
.pipe(gulp.dest('./css'));
});
// 合并,压缩文件:scripts任务会合并js/目录下得所有得js文件并输出到dist/目录,然后gulp会重命名、压缩合并的文件,也输出到dist/目录。
gulp.task('scripts', function() {
gulp.src('./js/*.js')
.pipe(concat('all.js'))
.pipe(gulp.dest('./dist'))
.pipe(rename('all.min.js'))
.pipe(uglify())
.pipe(gulp.dest('./dist'));
});
// 默认任务:这时,我们创建了一个基于其他任务的default任务。使用.run()方法关联和运行我们上面定义的任务,使用.watch()方法去监听指定目录的文件变化,当有文件变化时,会运行回调定义的其他任务。
gulp.task('default', function() {
gulp.run('lint', 'sass', 'scripts');
// 监听文件变化
gulp.watch('./js/*.js', function() {
gulp.run('lint', 'sass', 'scripts');
});
});
现在,回到命令行,可以直接运行gulp任务了 gulp 这将执行定义的default任务,换言之,这和以下的命令式同一个意思 gulp default
##模块加载
1.gulpfile.js中一一加载模块
gulpfile.js
var gulp = require('gulp'),
jshint = require('gulp-jshint'),
uglify = require('gulp-uglify'),
concat = require('gulp-concat');
gulp.task('js', function() {
return gulp.src('js/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(uglify())
.pipe(concat('app.js'))
.pipe(gulp.dest('build'));
});
2.使用gulp-load-plugins自动载入所有已安装的模块
使用gulp-load-plugins模块,可以加载package.json文件中所有的gulp模块。
package.json
{
"devDependencies": {
"gulp-concat": "~2.2.0",
"gulp-uglify": "~0.2.1",
"gulp-jshint": "~1.5.1",
"gulp": "~3.5.6"
}
}
gulpfile.js
var gulp = require('gulp'),
gulpLoadPlugins = require('gulp-load-plugins'),
plugins = gulpLoadPlugins();
gulp.task('js', function() {
return gulp.src('js/*.js')
.pipe(plugins.jshint())
.pipe(plugins.jshint.reporter('default'))
.pipe(plugins.uglify())
.pipe(plugins.concat('app.js'))
.pipe(gulp.dest('build'));
});
gulp.src()
gulp模块的src方法,用于产生数据流。它的参数表示所要处理的文件,一般有以下几种形式。
js/app.js:指定确切的文件名。 js/.js:某个目录所有后缀名为js的文件。 js/**/*.js:某个目录及其所有子目录中的所有后缀名为js的文件。 !js/app.js:除了js/app.js以外的所有文件。 *.+(js|css):匹配项目根目录下,所有后缀名为js或css的文件。 ['js/*/*.js', '!js/**/*.min.js']:还可以是一个数组,用来指定多个成员。
gulp.task()
gulp模块的task方法,用于定义具体的任务。它的第一个参数是任务名,第二个参数是任务函数
- 非常简单的任务函数:
gulp.task('greet', function() {
console.log('Hello world!');
});
- task方法还可以指定按顺序运行的一组任务:
gulp.task('css', function() {
console.log('css...');
});
gulp.task('js', function() {
console.log('js...');
});
gulp.task('imgs', function() {
console.log('imgs...');
});
gulp.task('build', ['css', 'js', 'imgs']);
上面代码先指定build任务,它按次序由css、js、imgs三个任务所组成。注意,由于每个任务都是异步调用,所以没有办法保证js任务的开始运行的时间,正是css任务运行结束。
- 任务严格按次序运行:
gulp.task('greet', function() {
console.log('Hello world!');
});
gulp.task('css', ['greet'], function() {
console.log('css...');
});
gulp.task('js', function() {
console.log('js...');
});
gulp.task('build', ['css', 'js']);
上面代码表明,css任务依赖greet任务,所以css一定会在greet运行完成后再运行。
- 默认任务:
gulp.task('default', function() {
// Your default task
});
如果一个任务的名字为default,就表明它是“默认任务”,在命令行直接输入gulp命令,就会运行该任务。
gulp.watch()
gulp模块的watch方法,用于指定需要监视的文件。一旦这些文件发生变动,就运行指定任务。
- watch方法
gulp.task('watch', function() {
gulp.watch('templates/*.tmpl.html', ['build']);
});
上面代码指定,一旦templates目录中的模板文件发生变化,就运行build任务。
- watch方法也可以用回调函数,代替指定的任务。
gulp.watch('templates/*.tmpl.html', function(event) {
console.log('Event type: ' + event.type);
console.log('Event path: ' + event.path);
});
- 另一种写法是watch方法所监控的文件发生变化时(修改、增加、删除文件),会触发change事件。可以对change事件指定回调函数。
var watcher = gulp.watch('templates/*.tmpl.html', ['build']);
watcher.on('change', function(event) {
console.log('Event type: ' + event.type);
console.log('Event path: ' + event.path);
});
除了change事件,watch方法还可能触发以下事件:
- end:回调函数运行完毕时触发。
- error:发生错误时触发。
- ready:当开始监听文件时触发。
- nomatch:没有匹配的监听文件时触发。
- watcher对象还包含其他一些方法。
- watcher.end():停止 watcher对象,不会再调用任务或回调函数。
- watcher.files():返回 watcher对象监视的文件。
- watcher.add(glob):增加所要监视的文件,它还可以附件第二个参数,表示回调函数。
- watcher.remove(filepath):从 watcher对象中移走一个监视的文件。
##模块
-
gulp-load-plugins模块(如上)
-
gulp-livereload:模块用于自动刷新浏览器,反映出源码的最新变化。它除了模块以外,还需要在浏览器中安装插件,用来配合源码变化。
var gulp = require('gulp'),
less = require('gulp-less'),
livereload = require('gulp-livereload'),
watch = require('gulp-watch');
gulp.task('less', function() {
gulp.src('less/*.less')
.pipe(watch())
.pipe(less())
.pipe(gulp.dest('css'))
.pipe(livereload());
});
上面代码监视less文件,一旦编译完成,就自动刷新浏览器。
自动载入(gulp-load-plugins) 编译Sass (gulp-ruby-sass) Autoprefixer (gulp-autoprefixer) 缩小化(minify)CSS (gulp-minify-css) JSHint (gulp-jshint) 拼接 (gulp-concat) 丑化(Uglify) (gulp-uglify) 图片压缩 (gulp-imagemin) 即时重整(LiveReload) (gulp-livereload) 清理档案 (gulp-clean) 图片快取,只有更改过得图片会进行压缩 (gulp-cache) 更动通知 (gulp-notify)
gulp-less : less gulp-ruby-sass : 支持sass gulp-minify-css : 压缩css gulp-jshint : 检查js gulp-uglify : 压缩js gulp-concat : 合并文件 gulp-rename : 重命名文件 gulp-htmlmin : 压缩html gulp-clean : 清空文件夹
执行下列指令来安装这些外挂:
$ npm install gulp-ruby-sass gulp-autoprefixer gulp-minify-css gulp-jshint gulp-concat gulp-uglify gulp-imagemin gulp-clean gulp-notify gulp-rename gulp-livereload gulp-cache --save-dev
指令将会安装必要的外挂,并纪录于package.json内的devDependencies物件。完整的gulp外挂清单可以在这裡找到。 http://gratimax.net/search-gulp-plugins
##配置事例
示例配置:Gulp 实现完整的 SASS 自动编译并刷新网页
// Include gulp
var gulp = require('gulp');
// Include Our Plugins
var sass = require('gulp-sass');
var lr = require('tiny-lr'),
refresh = require('gulp-livereload'),
server = lr();
// Task SASS
gulp.task('sass', function() {
gulp.src([
'scss/**/*.scss',
'!scss/**/_*.scss'
])
.pipe(sass({
includePaths: ['scss']
}))
.pipe(gulp.dest('css'))
.pipe(refresh(server));
});
gulp.task('refresh', function() {
gulp.src([
'**/*.html',
'**/*.php'
])
.pipe(refresh(server));
});
// Task: default
gulp.task('default', function() {
gulp.run('sass');
server.listen(35729, function(error) {
if (error) return console.log(error);
gulp.watch([
'scss/**',
'img/**'
], function(event) {
gulp.run('sass');
});
gulp.watch([
'**/*.html',
'**.php'
], function(event) {
gulp.run('refresh');
});
});
});
gulpfile.js
var gulp = require('gulp');
// 引入组件
var less = require('gulp-less'), // less
minifycss = require('gulp-minify-css'), // CSS压缩
uglify = require('gulp-uglify'), // js压缩
concat = require('gulp-concat'), // 合并文件
rename = require('gulp-rename'), // 重命名
clean = require('gulp-clean'); //清空文件夹
// less解析
gulp.task('build-less', function() {
gulp.src('./javis/static/less/lib/s-production.less')
.pipe(less())
.pipe(gulp.dest('./javis/static/build/css/lib/'))
gulp.src('./javis/static/less/lib/s-skins.less')
.pipe(less())
.pipe(gulp.dest('./javis/static/build/css/lib/'))
gulp.src('./javis/static/less/lib/s/s.less')
.pipe(less())
.pipe(gulp.dest('./javis/static/build/css/lib/'))
gulp.src('./javis/static/less/*.less')
.pipe(less())
.pipe(gulp.dest('./javis/static/build/css/'))
});
// 合并、压缩、重命名css
gulp.task('stylesheets', ['build-less'], function() {
// 注意这里通过数组的方式写入两个地址,仔细看第一个地址是css目录下的全部css文件,第二个地址是css目录下的areaMap.css文件,但是它前面加了!,这个和.gitignore的写法类似,就是排除掉这个文件.
gulp.src(['./javis/static/build/css/*.css', '!./javis/static/build/css/areaMap.css'])
.pipe(concat('all.css'))
.pipe(gulp.dest('./javis/static/build/css/'))
.pipe(rename({
suffix: '.min'
}))
.pipe(minifycss())
.pipe(gulp.dest('./javis/static/build/css'));
});
// 合并,压缩js文件
gulp.task('javascripts', function() {
gulp.src('./javis/static/js/*.js')
.pipe(concat('all.js'))
.pipe(gulp.dest('./javis/static/build/js'))
.pipe(rename({
suffix: '.min'
}))
.pipe(uglify())
.pipe(gulp.dest('./javis/static/build/js'));
});
// 清空图片、样式、js
gulp.task('clean', function() {
return gulp.src(['./javis/static/build/css/all.css', './javis/static/build/css/all.min.css'], {
read: false
})
.pipe(clean({
force: true
}));
});
// 将bower的库文件对应到指定位置
gulp.task('buildlib', function() {
gulp.src('./bower_components/angular/angular.min.js')
.pipe(gulp.dest('./javis/static/build/js/'))
gulp.src('./bower_components/angular/angular.js')
.pipe(gulp.dest('./javis/static/build/js/'))
gulp.src('./bower_components/bootstrap/dist/js/bootstrap.min.js')
.pipe(gulp.dest('./javis/static/build/js/'))
gulp.src('./bower_components/jquery/dist/jquery.min.js')
.pipe(gulp.dest('./javis/static/build/js/'))
gulp.src('./bower_components/angular-route/angular-route.min.js')
.pipe(gulp.dest('./javis/static/build/js/'))
gulp.src('./bower_components/angular-animate/angular-animate.min.js')
.pipe(gulp.dest('./javis/static/build/js/'))
gulp.src('./bower_components/angular-bootstrap/ui-bootstrap.min.js')
.pipe(gulp.dest('./javis/static/build/js/'))
gulp.src('./bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js')
.pipe(gulp.dest('./javis/static/build/js/'))
//--------------------------css-------------------------------------
gulp.src('./javis/static/less/fonts/*')
.pipe(gulp.dest('./javis/static/build/css/fonts/'))
gulp.src('./bower_components/bootstrap/fonts/*')
.pipe(gulp.dest('./javis/static/build/css/fonts/'))
gulp.src('./bower_components/bootstrap/dist/css/bootstrap.min.css')
.pipe(gulp.dest('./javis/static/build/css/lib'))
});
// 定义develop任务在日常开发中使用
gulp.task('develop', function() {
gulp.run('buildlib', 'build-less', 'javascripts', 'stylesheets');
gulp.watch('./javis/static/less/*.less', ['build-less']);
});
// 定义一个prod任务作为发布或者运行时使用
gulp.task('prod', function() {
gulp.run('buildlib', 'build-less', 'stylesheets', 'javascripts');
// 监听.less文件,一旦有变化,立刻调用build-less任务执行
gulp.watch('./javis/static/less/*.less', ['build-less']);
});
// gulp命令默认启动的就是default认为,这里将clean任务作为依赖,也就是先执行一次clean任务,流程再继续.
gulp.task('default', ['clean'], function() {
gulp.run('develop');
});
##gulp 与 Grunt
gulpfile.js
/*!
* gulp
* $ 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
*/
// Load plugins
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');
// Styles
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'
}));
});
// Scripts
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'
}));
});
// Images
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'
}));
});
// Clean
gulp.task('clean', function(cb) {
del(['dist/assets/css', 'dist/assets/js', 'dist/assets/img'], cb)
});
// Default task
gulp.task('default', ['clean'], function() {
gulp.start('styles', 'scripts', 'images');
});
// Watch
gulp.task('watch', function() {
// Watch .scss files
gulp.watch('src/styles/**/*.scss', ['styles']);
// Watch .js files
gulp.watch('src/scripts/**/*.js', ['scripts']);
// Watch image files
gulp.watch('src/images/**/*', ['images']);
// Create LiveReload server
livereload.listen();
// Watch any files in dist/, reload on change
gulp.watch(['dist/**']).on('change', livereload.changed);
});
Gruntfile.js
/*!
* Grunt
* $ npm install grunt-contrib-uglify grunt-autoprefixer grunt-contrib-cssmin grunt-contrib-imagemin grunt-contrib-sass grunt-contrib-watch grunt-contrib-concat grunt-contrib-clean grunt-contrib-jshint grunt-notify --save-dev
*/
module.exports = function(grunt) {
grunt.initConfig({
// Sass
sass: {
dist: {
options: {
style: 'expanded'
},
files: {
'dist/styles/main.css': 'src/styles/main.scss'
}
}
},
// Autoprefix
autoprefixer: {
options: {
browsers: [
'last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'
]
},
dist: {
src: 'dist/styles/main.css'
}
},
// CSS minify
cssmin: {
dist: {
files: {
'dist/styles/main.min.css': 'dist/styles/main.css'
}
}
},
// JShint
jshint: {
files: ['src/scripts/**/*.js'],
options: {
jshintrc: '.jshintrc'
}
},
// Concat
concat: {
js: {
src: ['src/scripts/**/*.js'],
dest: 'dist/scripts/main.js'
},
},
// Uglify
uglify: {
dist: {
src: 'dist/scripts/main.js',
dest: 'dist/scripts/main.min.js'
},
},
// Imagemin
imagemin: {
dist: {
options: {
optimizationLevel: 3,
progressive: true,
interlaced: true
},
files: [{
expand: true,
cwd: 'src/images',
src: ['**/*.{png,jpg,gif}'],
dest: 'dist/images'
}]
}
},
// Clean
clean: {
build: ['dist/styles', 'dist/scripts', 'dist/images']
},
// Notify
notify: {
styles: {
options: {
message: 'Styles task complete',
}
},
scripts: {
options: {
message: 'Scripts task complete',
}
},
images: {
options: {
message: 'Images task complete',
}
},
},
// Watch
watch: {
styles: {
files: 'src/styles/**/*.scss',
tasks: ['sass', 'autoprefixer', 'cssmin', 'notify:styles'],
},
scripts: {
files: 'src/scripts/**/*.js',
tasks: ['concat', 'uglify', 'notify:scripts'],
},
images: {
files: 'src/images/**/*',
tasks: ['imagemin', 'notify:images'],
},
livereload: {
options: {
livereload: true
},
files: [
'dist/styles/**/*.css',
'dist/scripts/**/*.js',
'dist/images/**/*'
]
}
}
});
// Default task
grunt.registerTask('default', [
'jshint',
'clean',
'concat',
'uglify',
'sass',
'autoprefixer',
'cssmin',
'imagemin'
]);
// Load plugins
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-autoprefixer');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-imagemin');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-notify');
};