gulp

137 阅读6分钟

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文件加工的转换流是通过独立的插件完成 自动化构建流程:

  1. gulp提供的API方法——src创建文件读取流
  2. 通过插件提供的转换流实现文件的加工
  3. 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')
  1. 样式编译(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))
}
  1. 脚本文件(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') -->

  1. 页面文件(模板文件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'))
}
<!-- 模板引擎中存在需要替换的数据 -->
  1. 创建组合任务
<!-- module.exports={
    style,
    script,
    page
} -->
<!-- 因为在需要进行同时运行 三个任务需要同时进行parallel-->
const {parallel}=require('gulp')
const compile=parallel(style,script,page)
module.exports={
    compile
}
  1. 图片和字体文件转换(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'))
}
  1. 其他文件及文件清除 额外文件
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))
  1. 自动加载插件 简化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文件压缩

  1. 分别压缩HTML、CSS、JavaScript(gulp-htmlmin gulp-uglify gulp-clean-css )
  2. 通过判断来决定什么文件用什么压缩插件(gulp-if)
  3. 压缩需要在上线之前(要先执行html、css、js等构件任务再执行压缩)
  4. 由于会出现文件读写混乱、冲突(即读是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补充

  1. 在package.json中通过scripts将任务引出
 "scripts": {
    "clean": "gulp clean",
    "serve": "gulp serve",
    "build": "gulp build"
  },

2.在gitignore文件中忽略dist目录和tem目录

dist/
temp/