1. 基本使用
- yarn init -y
- yarn add gulp --dev(gulp是作为开发依赖安装的,grunt是以生产环境依赖安装的)
- 根目录下新建gulpfile.js
- gulp4.0之前的写法(如下),被保留,但不推荐这种写法
const gulp = require('gulp')
gulp.task('bar', done => {
console.log('bar working~')
done()
})
- gulp4.0之后的写法(直接导出任务的形式),推荐
exports.foo = done => {
console.log('aaa')
done()
}
exports.default = done => {
console.log('tag')
done()
}
- 运行命令:yarn gulp bar/yarn gulp foo/yarn gulp
2. gulp的组合任务
- 除了创建普通任务以外,gulp还提供了series和paralled两个用来创建组合任务的api
- series用来创建串行任务,parallel用来创建并行任务
- 执行命令:yarn gulp foo/yarn gulp bar
- series和parallel在实际创建工作流中非常有用,例如,我们编译css任务和编译js任务是互不干扰的,那这两个任务就可以通过并行的任务去执行,可以提高构建效率;部署的时候,需要先执行编译任务,这时候可以通过series这种串行的api去执行任务
const { series, parallel } = require('gulp')
const task1 = done => {
setTimeout(() => {
console.log('task1 working~')
done()
}, 1000)
}
const task2 = done => {
setTimeout(() => {
console.log('task2 working')
done()
}, 1000)
}
const task3 = done => {
setTimeout(() => {
console.log('tag', 'task3 working~')
done()
}, 1000)
}
exports.foo = series(task1, task2, task3)
exports.bar = parallel(task1, task2, task3)
3. gulp的异步任务
- 异步任务的实现方式:回调、promise、async、文件流
const fs = require('fs')
exports.callback = done => {
console.log('callback task~', '')
done()
}
exports.callback_error = done => {
console.log('callback task error~')
done(new Error('error'))
}
exports.promise = () => {
console.log('promise task finished~')
return Promise.resolve()
}
exports.promise_error = () => {
console.log('promise task error~')
return Promise.reject(new Error('promsie error'))
}
exports.async = async () => {
await timeout(1000)
console.log('tag', 'async task~')
}
exports.stream = () => {
const readStream = fs.createReadStream('package.json')
const writeSteam = fs.createWriteStream('temp.txt')
readStream.pipe(writeSteam)
return readStream
}
4. gulp构建过程核心工作原理
- 构建过程大多数都是将文件读出来,然后进行转换操作,最后写入到另外一个位置
- 通过 读取流--》转换流 --》写入流 的流程实现
- 接下来通过node底层api来实现压缩css的过程(以下有css代码展现)
const fs = require('fs')
const {Transform} = require('stream')
exports.default = () => {
// 读取流
const readStream = fs.createReadStream('normalize.css')
// 转换流
const transform = new Transform({
transform: (chunk, encoding, callback) => {
console.log('chunk', chunk)
const input = chunk.toString()
console.log('chunked', input)
const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')
callback(null, output)
}
})
// 写入流
const writeStream = fs.createWriteStream('normalize.min.csss')
readStream
.pipe(transform)
.pipe(writeStream)
return readStream
}
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
fieldset {
padding: 0.35em 0.75em 0.625em;
}
legend {
box-sizing: border-box;
color: inherit;
display: table;
max-width: 100%;
padding: 0;
white-space: normal;
}
5. gulp文件操作api
- gulp中提供了专用去创建读取流和写入流的api,相比于底层node的api更强大也更容易使用。至于负责文件加工的转换流,绝大多数都是使用独立的插件来实现
- gulp 通过src方法创建读取流,再借助插件提供的转换流实现文件加工,最后提供gulp提供的dest方法实现一个写入流,从而写入到目标文件
- yarn add gulp-clean-css --dev 安装此依赖作用:压缩css
- yarn add gulp-rename --dev 此依赖作用:重命名扩展名
const { src, dest } = require('gulp')
const cleanCss = require('gulp-clean-css')
const rename = require('gulp-rename')
exports.default = () => {
return src('*.css')
.pipe(cleanCss())
.pipe(rename({ extname: '.min.css' }))
.pipe(dest('dist'))
}
6. gulp案例(02-01-03-12-zce-gulp-demo)- 样式编译
- 根目录下的public,就是我们在开发网页应用当中那些不需要被加工的直接去拷贝到我们最终生成的文件夹的一些文件
- 图片和字体文件压缩:图片中是有一些二进制的原数据信息,那些信息在生产环境是没有必要的,这些信息都可以通过自动化构建的过程给删除掉,从而压缩文件的体积
- js 将es6转换成es5
- yarn add gulp --dev
- yarn add gulp-sass --dev 安装gulp-sass的时候,内部会去安装node-sass,node-sass是C++的模块,内部会有对C++程序集的依赖,所以一些二进制的包需要通过外国的站点去下载,所以有的时候会下载不下来,可以单独为node-sass配置一个镜像
- gulp-sass五版本以上需要手动安装sass,用法与4不同
const { src, dest } = require('gulp')
const sass = require('gulp-sass')(require('sass'))
const style = () => {
return src('src/assets/styles/**', { base: 'src'})
.pipe(sass({ outputStyle: 'expanded'}))
.pipe(dest('dist'))
}
module.exports = {
style
}
7. gulp案例 - 脚本编译
- yarn add gulp-babel --dev
- yarn add @babel/core @babel/preset-env --dev
- preset-env默认会把es6模块的新特性都会做转换
const { src, dest } = require('gulp')
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const style = () => {
return src('src/assets/styles/*.scss', { base: 'src'})
.pipe(sass({ outputStyle: 'expanded'}))
.pipe(dest('dist'))
}
const script = () => {
return src('src/assets/scripts/*.js', {base: 'src'})
.pipe(babel({ presets: ['@babel/preset-env']}))
.pipe(dest('dist'))
}
module.exports = {
style,
script
}
8. gulp案例 - 页面模板编译
- 模板引擎插件 yarn add gulp-swig --dev
- 可以自定义data放到swig配置项里,实现全局动态渲染模板
const { src, dest, series, parallel } = require('gulp')
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const swig = require('gulp-swig')
const style = () => {
return src('src/assets/styles/*.scss', { base: 'src'})
.pipe(sass({ outputStyle: 'expanded'}))
.pipe(dest('dist'))
}
const script = () => {
return src('src/assets/scripts/*.js', {base: 'src'})
.pipe(babel({ presets: ['@babel/preset-env']}))
.pipe(dest('dist'))
}
const page = () => {
return src('src/*.html', {base: 'src'})
.pipe(swig({ data }))
.pipe(dest('dist'))
}
const compile = parallel(style, script, page)
module.exports = {
compile
}
9. gulp案例 - 图片和字体文件转换、其他文清除
- yarn add gulp-imagemin --dev 图片是无损压缩,也就是说看到的结果是不会受影响的,只是删除了一些原数据的信息
- yarn add del --dev 清除文件
- yarn add gulp-load-plugins --dev 自动加载插件
const { src, dest, series, parallel } = require('gulp')
const del = require('del')
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
const data = {}
const clean = () => {
return del(['dist'])
}
const style = () => {
return src('src/assets/styles/*.scss', { base: 'src'})
.pipe(plugins.sass({ outputStyle: 'expanded'}))
.pipe(dest('dist'))
}
const script = () => {
return src('src/assets/scripts/*.js', {base: 'src'})
.pipe(plugins.babel({ presets: ['@babel/preset-env']}))
.pipe(dest('dist'))
}
const page = () => {
return src('src/*.html', {base: 'src'})
.pipe(plugins.swig({ data }))
.pipe(dest('dist'))
}
const image = () => {
return src('src/assets/images/**', { base: 'src' })
.pipe(plugins.imagemin())
.pipe(dest('dist'))
}
const font = () => {
return src('src/assets/fonts/**', { base: 'src'})
.pipe(plugins.imagemin())
.pipe(dest('dist'))
}
const extra = () => {
return src('public/**', { base: 'public'})
.pipe(dest('dist'))
}
const compile = parallel(style, script, page, image, font)
const build = series(clean, parallel(compile, extra))
module.exports = {
clean,
compile,
build
}
10. gulp案例 - 开发服务器
const { src, dest, parallel, series, watch } = require('gulp')
const del = require('del')
const browserSync = require('browser-sync')
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
const bs = browserSync.create()
const data = {
menus: [
{
name: 'Home',
icon: 'aperture',
link: 'index.html'
},
{
name: 'Features',
link: 'features.html'
},
{
name: 'About',
link: 'about.html'
},
{
name: 'Contact',
link: '#',
children: [
{
name: 'Twitter',
link: 'https://twitter.com/w_zce'
},
{
name: 'About',
link: 'https://weibo.com/zceme'
},
{
name: 'divider'
},
{
name: 'About',
link: 'https://github.com/zce'
}
]
}
],
pkg: require('./package.json'),
date: new Date()
}
const clean = () => {
return del(['dist', 'temp'])
}
const style = () => {
return src('src/assets/styles/*.scss', { base: 'src' })
.pipe(plugins.sass({ outputStyle: 'expanded' }))
.pipe(dest('temp'))
.pipe(bs.reload({ stream: true }))
}
const script = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
.pipe(dest('temp'))
.pipe(bs.reload({ stream: true }))
}
const page = () => {
return src('src/*.html', { base: 'src' })
.pipe(plugins.swig({ data, defaults: { cache: false } }))
.pipe(dest('temp'))
.pipe(bs.reload({ stream: true }))
}
const image = () => {
return src('src/assets/images/**', { base: 'src' })
.pipe(plugins.imagemin())
.pipe(dest('dist'))
}
const font = () => {
return src('src/assets/fonts/**', { base: 'src' })
.pipe(plugins.imagemin())
.pipe(dest('dist'))
}
const extra = () => {
return src('public/**', { base: 'public' })
.pipe(dest('dist'))
}
const serve = () => {
watch('src/assets/styles/*.scss', style)
watch('src/assets/scripts/*.js', script)
watch('src/*.html', page)
watch([
'src/assets/images/**',
'src/assets/fonts/**',
'public/**'
], bs.reload)
bs.init({
notify: false,
port: 2080,
// open: false,
// files: 'dist/**',
server: {
baseDir: ['temp', 'src', 'public'],
routes: {
'/node_modules': 'node_modules'
}
}
})
}
const useref = () => {
return src('temp/*.html', { base: 'temp' })
.pipe(plugins.useref({ searchPath: ['temp', '.'] }))
.pipe(plugins.if(/\.js$/, plugins.uglify()))
.pipe(plugins.if(/\.css$/, plugins.cleanCss()))
.pipe(plugins.if(/\.html$/, plugins.htmlmin({
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true
})))
.pipe(dest('dist'))
}
const compile = parallel(style, script, page)
const build = series(
clean,
parallel(
series(compile, useref),
image,
font,
extra
)
)
const develop = series(compile, serve)
module.exports = {
clean,
build,
develop
}