gulp 使用
1.通过yarn init的方式初始化项目yarn init --yes
2.安装gulp的依赖 yarn add gulp --dev
3.在根目录中创建gulpfile.js文件(定义gulp需要定义的构建任务)
4.在gulpfile.js文件中通过exports导出函数的方式进行构建
5.通过yarn gulp <函数名称> (yarn gulp foo)运行
因为在最新的gulp中的取消同步代码模式,约定每个任务都是异步任务,需要通过回调函数的来标记任务是否完成
6.在gulp4.0之前的版本需要通过gulp中的方法来注册gulp中的任务(gulp.task的方法来进行注册)
gulp的组合任务(series(异步任务) parallel(同步执行任务))
应用场景:
1.编译css和js的任务,通过并行的方式(parallel)
2.部署-先需要进行编译的操作需要串行的方式(series)
gulp异步任务的三种方式
回调的方式处理
exports.callback=done=>{
console.log('callback task~')
done()
}
<!-- 错误处理的方式 -->
exports.callback_erroe=done=>{
console.log('callback error')
done(new Error('task failed!'))
}
promise方式处理
exports.promise=()=>{
console.log('promise task')
return Promise.resolve()
}
<!--错误处理方式 -->
exports.promise_error=()=>{
console.log('promise task')
return Promise.reject(new Error('task failed'))
}
async await 方式处理(前提是必须是node8.0以上的版本)
const timeout=time=>{
return new Promise(resolve=>{
setTimeout(resolve,time)
})
}
exports.async=async()=>{
await timeout(1000)
console.log('async task')
}
stream方式处理(最常用的方式处理)
const fs=require('fs')
expports.stream=()=>{
const readStream=fs.createReadStream('package.json')
const writeStream=fs.createWriteStream('temp.txt')
<!-- 通过pipe将读取的文件(readStream)注册(导入)到writeStream中 -->
readStream.pipe(writeStream)
return readStream
}
gulp构建过程核心工作原理
输入(读取流)——>加工(转换流)——>输出(写入流)
<!-- 引用文件读写模块 -->
const fs=require('fs')
<!-- 引入文件转换 -->
const{Transform}=require('stream')
exports.default=()=>{
<!-- 读取文件内容(文件读取流) -->
const read=fs.createReadStream('normalize.css')
<!-- 文件转换过程(转换流) -->
const transform=new Transform({
transform:(chunk,encoding,callback)=>{
//核心转换过程实现
// chunk=>读取流中读取到的内容(Buffer)
const input=chunk.toString()
const output=input.replace(/\s+/g,'').replace(/\/\*.+?\*\//g,'')
callback(null,output) //错误优先的函数,第一个参数中错误信息内容,无用null
}
})
// 文件输出流
const write=fs.createWriteStream('normalize.min.css')
// 把读取出来的文件流导入写入文件流
read
.pipe(transform)//转换
.pipe(write)//写入
return read
}
gulp文件操作API+插件的使用
gulp文件加工的转换流是通过独立的插件完成 自动化构建流程:
- gulp提供的API方法——src创建文件读取流
- 通过插件提供的转换流实现文件的加工
- gulp提供的API方法-dest创建文件的写入流,写入到目标文件
// 自动化构建流程
// gulp提供src创建文件的读取流
// dest创建文件的写入流
const {src,dest}=require('gulp')
// 文件的转换流可以通过插件gulp-clean-css(可以压缩css文件转换流)
const cleanCss=require('gulp-clean-css')
// 重命名
const rename=require('gulp-rename')
exports.default=()=>{
// src('src/*.css')可以通过通配符找到src目录下所有的css文件
return src('src/normalize.css') //读取src文件下的normalize文件
.pipe(cleanCss())//先进行转换再进入到写入流中
//可以在此中间可以进行多个转换操作(pipe操作)
.pipe(rename({extname:'.min.css'}))//extname参数可以指定扩展名为.min.css
.pipe(dest('dist'))//通过pipe方法导入到dest写入流中-dest方法中只用传入写入的目标文件-输出文件
}
gulp案例(gulpfile.js)
const {src,dest}=require('gulp')
- 样式编译(gulp-sass --dev会自动安装node-sass模块)
const sass=require('gulp-sass)
const style=()=>{
return src('src/assets/styles/*.scss',{base:'src'})//src方法后第二个参数-选项参数base可以指定基准路径(保留src中里面的所有的文件目录)
.pipe(sass())//如果想生成的css文件中样式结束时的中括号为单行时,可以在sass方法中添加参数进行设置(sass({outputStyle:'expanded'}))
.pipe(dest('dist))
}
- 脚本文件(es6的编译)js(gulp-babel --dev不会自动安装@babel/core @babel/preset-env --dev需要手动安装)
const babel=require('gulp-babel')
const script=()=>{
return src('src/assets/scripts/*.js',{base:'src'})
.pipe(babel({presets:['@babel/preset-env']))//必须传入present参数,若不传会导致js文件不会进行转换
.pipe(dest('dist))
}
<!-- 注意错误(cannot find modules '@babel/core') -->
- 页面文件(模板文件html)例子为swig模板引擎(gulp-swig --dev)
const swig=require('gulp-swig')
const page=()=>{
return src('src/*.html',{base:'src'})
//return src('src/**/*.html')//如果html文件在src目录中很多文件中存在,则需要使用**/*.html(任意子目录文件下的html文件)
.pipe(swig({data}))//如果模板引擎存在需要替换的数据直接传入数据结构{data:data}
.pipe(dest('dist'))
}
<!-- 模板引擎中存在需要替换的数据 -->
- 创建组合任务
<!-- module.exports={
style,
script,
page
} -->
<!-- 因为在需要进行同时运行 三个任务需要同时进行parallel-->
const {parallel}=require('gulp')
const compile=parallel(style,script,page)
module.exports={
compile
}
- 图片和字体文件转换(gulp-imagemin --dev)
const imagemin=require('gulp-imagemin')
<!-- 图片压缩 -->
const image=()=>{
return src('src/assets/image/**',{base:'src'})//**可以匹配image目录下的所有文件
.pipe(imagemin())
.pipe(dest('dist'))
}
<!-- 压缩字体 -->
const font=()=>{
return src('src/assets/font/**,{base:'src'})
.pipe(imagemin())
.pipe(dest('dist'))
}
- 其他文件及文件清除 额外文件
const extra=()=>{
return src('public/**',{base:'public'})
.pipe(dest('dist'))
}
组合构建
const compile=parallel(style,script,page,image,font)
const build=parallel(compile,extra)
module.exports={
build
}
清除文件(del --dev)
const del=require('del')
const clean=()=>{
return del(['dist'])
}
<!-- 由于需要先删除dist文件中文件才能build,需要使用series -->
const build=series(clean,parallel(compile,extra))
- 自动加载插件 简化require导入(gulp-load-plugins --dev)
const loadPlugins=require('gulp-load-plugins')
const plugins=loadPlugins()
<!-- 可以直接在构建任务中使用plugins.XXX结构 -->
例:const babel=require('gulp-babel')==>plugins.babel
const babel=require('gulp-babel-aaaa)==>plugins.babelAaaa(如果插件后面有上面这样,需要将后的首字母变成大写字母)
//const font=()=>{
//return src('src/assets/font/**,{base:'src'})
//.pipe(imagemin())
//.pipe(dest('dist'))
//}===>>>>
const font=()=>{
return src('src/assets/fonts/**',{base:'src})
.pipe(plugins.imagemin())
.pipe(dest('dist'))
}
热更新开发服务器(browser-sync --dev)
const browserSync=require('browser-sync')
const bs=browseraSync.create()
const serve=()=>{
bs.init({
notify:false,//关闭页面的小提示
port:2080,//设置页面的端口号
open:false,//是否自动打开浏览器
files:'dist/**',//指定目录下,文件改变了自动更新浏览器上的页面(注意只能更新不需要编译的文件(src下的目录文件))
server:{//核心配置
baseDir:'dist',//网站的根目录
//<!-- 注意直接从node_modules中直接引入的可能无法呈现相应的效果 -->加特效路由routes( 会优先于baseDir配置,先去看routes配置,再看baseDir配置——路由映射)
routes:{//相对路径,相对于网站中的根目录
'/node_modules':'node_modules'
}
}
})
}
监视变化及构建过程优化
<!-- 由于无法自动编译修改后的src中的源代码需要使用gulp中的watch方法 -->
const {watch}=require('gulp')//watch方法会自动监视一个文件路径,根据文件的变化是否重新执行某个编译任务
const serve=()=>{
watch('src/assets/styles/*.scss',style)
<!-- 静态资源,无需执行编译任务 -->
watch([
'src/assets/images/**',
'src/assets/fonts/**',
'public/**'
],bs.reload)//reload是brower-sync提供的一个监控文件更新的方法
bs.init({
notify:false,//关闭页面的小提示
port:2080,//设置页面的端口号
open:false,//是否自动打开浏览器
//files:'dist/**',//第一种监视文件更新的方式
server:{//核心配置
baseDir:'dist',//网站的根目录
routes:{//相对路径,相对于网站中的根目录
'/node_modules':'node_modules'
}
})
}
实例:
const style=()=>{
return src('src/assets/style/*.scss',{base:'src'})
.pipe(plugin.sass({outputStyle:"expaned"}))
.pipe(base('dist'))
.pipe(bs.reload({stream:true}))
}
html中文件引用处理(gulp-useref)
处理任务内容为上下两个注释,一个build一个endbuild
<!-- build:css assets/styles/vendor.css -->
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css">
<!-- endbuild -->
const useref=()=>{
return src('dist/*.html',{base:'dist'})
.pipe(plugin.useref({searchPath:['dist','.]}))
.pipe(base('dist'))
}
html/css/js文件压缩
- 分别压缩HTML、CSS、JavaScript(gulp-htmlmin gulp-uglify gulp-clean-css )
- 通过判断来决定什么文件用什么压缩插件(gulp-if)
- 压缩需要在上线之前(要先执行html、css、js等构件任务再执行压缩)
- 由于会出现文件读写混乱、冲突(即读是dist目录写也是dist目录)将写入文件归还成另外一个即可
创建压缩任务
const useref=()=>{
return src('dist/*.html',{base:'dist'})
.pipe(plugin.useref({searchPath:['dist','.']}))
.pipe(plugin.if(/\.js$/,plugin.uglify()))//gulp-if中的if方法的第一次参数是一个正则表达式,第二个参数是需要工作的转换流
// .pipe(plugin.if(/\.html$/,plugin.htmlmin()))//直接运行htmlmin只会删除属性之间中的空白符但是换行符是不会进行删除操作
// 需要在htmlmin中添加参数进行压缩操作
.pipe(plugin.if(/\.html$/,plugin.htmlmin({
collapseWhitespace:true,
minifyCss:true,//压缩html中的css
minifyJs:true,//压缩html中的js
})))
.pipe(plugin.if(/\.css$/,plugin.cleanCss()))
// .pipe(dest('dist'))
.pipe(dest('release'))
}
gulp补充
- 在package.json中通过scripts将任务引出
"scripts": {
"clean": "gulp clean",
"serve": "gulp serve",
"build": "gulp build"
},
2.在gitignore文件中忽略dist目录和tem目录
dist/
temp/