Gulp使用node.js流,由于它不需要將臨時文件/文件夾寫入磁盤,構(gòu)建起來速度更快。Gulp允許你輸入你的源文件,通過一堆插件管理它們,并在最后得到一個輸出,而Grunt則為每一個插件配置一個輸入和輸出。下面我們先看看Grunt和Gulp的一個基本使用Sass構(gòu)建的樣子:
Grunt:
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:
gulp.task('sass', function() {
return sass('src/styles/main.scss', { 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'))
});
我們只用輸入一個文件,它被Sass插件修改后,傳遞給Autoprefixer插件并修改,然后我們得到一個文件。這個構(gòu)建過程更快,因為我們沒有讀取和寫入不必要的文件。
下面我們創(chuàng)建一個基本的gulp文件,其中包含一些核心任務(wù)。
$ npm install gulp -g
或者
// 進到你的項目文件比如gulp-demo
// cd gulp-demo
$ npm install gulp --save-dev
這會將gulp本地安裝到項目中,并將其保存到package.json文件中的devDependencies。
安裝gulp插件
- 編譯Sass文件 (gulp-ruby-sass)
- 根據(jù)設(shè)置瀏覽器版本自動處理瀏覽器前綴 (gulp-autoprefixer)
- 壓縮CSS (gulp-cssnano)
- 語法檢查工具 (gulp-jshint)
- 合并文件 (gulp-concat)
- 壓縮JS (gulp-uglify)
- 壓縮圖片 (gulp-imagemin)
- 自動刷新 (gulp-connect)
- 緩存圖片,僅壓縮被更改的圖片 (gulp-cache)
- 通知變化 (gulp-notify)
- 編譯前清理文件 (del)
$ npm install gulp-ruby-sass gulp-autoprefixer gulp-cssnano gulp-jshint gulp-concat gulp-uglify gulp-imagemin gulp-notify gulp-rename gulp-connect gulp-cache del --save-dev
加載插件
首先,創(chuàng)建一個gulpfile.js文件
touch gulpfile.js
然后添加以下內(nèi)容
var gulp = require('gulp'),
sass = require('gulp-ruby-sass'),
autoprefixer = require('gulp-autoprefixer'),
cssnano = require('gulp-cssnano'),
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'),
del = require('del'),
connect = require('gulp-connect');//livereload
Gulp插件與Grunt插件略有不同 - 它們被設(shè)計用來完成一件事,一件事。比如Grunt的imagemin使用緩存來避免重新壓縮已經(jīng)被壓縮的圖像。而Gulp可以用一個緩存插件完成,也可以用來緩存其他的東西。 這為構(gòu)建過程增加了額外的靈活性。
我們可以像Grunt一樣自動加載所有安裝的插件,但為了本文的目的,我們將堅持手動方法。
創(chuàng)建任務(wù)
實時更新
gulp.task('connect', function () {
connect.server({
livereload: true
});
});
編譯Sass,自動處理前綴,壓縮CSS
gulp.task('styles', function() {
return sass('src/styles/main.scss', { style: 'expanded' })
.pipe(autoprefixer('last 2 version'))
.pipe(gulp.dest('dist/assets/css'))
.pipe(rename({suffix: '.min'}))
.pipe(cssnano())
.pipe(gulp.dest('dist/assets/css'))
.pipe(notify({ message: 'Styles task complete' }))
.pipe(connect.reload())
});
這里先稍作解釋
gulp.task('styles', function() { ... )};
gulp.task這是用來創(chuàng)建任務(wù)的API。 你可以在終端單獨執(zhí)行命令$ gulp styles
return sass('src/styles/main.scss', { style: 'expanded' })
這是我們定義源文件并傳遞任何選項的新gulp-ruby-sass API。對于許多其他的插件,你可以使用我們稍后在這篇文章中使用的gulp.src API(return gulp.src(...))。它也可以是glob模式,比如/*/.scss來匹配多個文件。 通過返回流使它異步,確保任務(wù)完全完成,然后我們收到通知說完成。
.pipe(autoprefixer('last 2 version'))
我們使用.pipe()將源文件傳送到插件中。
.pipe(gulp.dest('dist/assets/css'));
gulp.dest API是我們設(shè)置目標路徑的地方。一個任務(wù)可以有多個目標,一個輸出擴展版本,另一個輸出minifed版本。 這在上面的樣式任務(wù)中得到了證明。
校驗語法, 合并文件, 壓縮JS
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' }))
.pipe(connect.reload())
});
這里我們使用gulp.src API來指定我們的輸入文件。
定義Html任務(wù)
gulp.task('html', function () {
return gulp.src('src/*.html')
.pipe(gulp.dest('dist'))
.pipe(connect.reload());
});
壓縮圖片
gulp.task('images', function() {
return gulp.src('src/images/**/*')
.pipe(cache(imagemin({ optimizationLevel: 5, progressive: true, interlaced: true })))
.pipe(gulp.dest('dist/assets/img'))
.pipe(notify({ message: 'Images task complete' }))
.pipe(connect.reload())
});
清理
在部署之前,清理目標文件夾并重建文件是一個好習慣 - 可以防止源文件中已經(jīng)刪除的留在目標文件夾中:
gulp.task('clean', function() {
return del(['dist/styles', 'dist/scripts', 'dist/images', 'dist/html']);
});
我們不需要在這里使用gulp插件,因為我們可以直接在gulp中利用Node模塊。我們使用return來確保任務(wù)在退出之前完成。
監(jiān)控
要監(jiān)控我們的文件并在更改時執(zhí)行必要的任務(wù),我們首先需要創(chuàng)建一個新任務(wù),然后使用gulp.watch API開始監(jiān)控文件:
gulp.task('watch', function() {
// 監(jiān)控 .scss 文件
gulp.watch('src/styles/**/*.scss', ['styles']);
// 監(jiān)控 .js 文件
gulp.watch('src/scripts/**/*.js', ['scripts']);
// 監(jiān)控圖片文件
gulp.watch('src/images/**/*', ['images']);
// 監(jiān)控 .html文件
gulp.watch('src/*.html', ['html']);
});
我們通過gulp.watch API指定要觀看的文件,并通過依賴數(shù)組定義要運行的任務(wù)。我們現(xiàn)在可以運行$ gulp watch
,任何對.scss,.js或圖像文件的更改都將運行它們各自的任務(wù)。
默認任務(wù)
我們可以創(chuàng)建一個默認任務(wù),使用$ gulp
運行,運行我們創(chuàng)建的所有三個任務(wù):
gulp.task('default', ['clean'], function() {
gulp.start('styles', 'scripts', 'html', 'images', 'watch', 'connect');
});
注意gulp.task中的附加數(shù)組。這是我們可以定義任務(wù)依賴關(guān)系的地方。在這個例子中,clean任務(wù)將在gulp.start中的任務(wù)之前運行。
注意:建議不要使用gulp.start來執(zhí)行依賴項arrary中的任務(wù),但是在這種情況下為了確保clean完全完成,這似乎是最好的選擇。
最終gulpfile.js文件
var gulp = require('gulp'),
sass = require('gulp-ruby-sass'),
autoprefixer = require('gulp-autoprefixer'),
cssnano = require('gulp-cssnano'),
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'),
del = require('del'),
connect = require('gulp-connect');//livereload
// Styles
gulp.task('styles', function () {
return sass('src/styles/main.scss', { style: 'expanded' })
.pipe(autoprefixer('last 2 version'))
.pipe(gulp.dest('dist/styles'))
.pipe(rename({ suffix: '.min' }))
.pipe(cssnano())
.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' }))
.pipe(connect.reload())
});
// Html
gulp.task('html', function () {
return gulp.src('src/*.html')
.pipe(gulp.dest('dist'))
.pipe(connect.reload());
});
// 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' }))
.pipe(connect.reload())
});
// Clean
gulp.task('clean', function () {
return del(['dist/styles', 'dist/scripts', 'dist/images', 'dist/html']);
});
// Default task
gulp.task('default', ['clean'], function () {
gulp.start('styles', 'scripts', 'html', 'images', 'watch', 'connect');
});
// Livereload
gulp.task('connect', function () {
connect.server({
livereload: true
});
});
// Watch
gulp.task('watch', function () {
gulp.watch('src/styles/**/*.scss', ['styles']);
gulp.watch('src/scripts/**/*.js', ['scripts']);
gulp.watch('src/images/**/*', ['images']);
gulp.watch('src/*.html', ['html']);
});