仅作为拉勾大前端的学习记录
gulp的基本使用
yarn init --yes
初始化package.json 文件yarn add gulp --dev
安装gulp包- 创建gulpfile.js 作为gulp 的入口文件
// gulpfile.js文件是 gulp的入口文件 exports.foo = function(done){ console.log("hello foo") done() } // 默认任务 exports.default = function(done){ console.log("hello default") done() }
gulp的组合任务
const { series, parallel } = require('gulp') const task1 = done => { setTimeout(() => { console.log('task1'); done(); },1000) } const task2 = done => { setTimeout(() => { console.log('task2'); done(); },1000) } exports.default = series(task1, task2) // 串行任务执行 exports.bar = parallel(task1, task2) // 并行任务执行
gulp的异步任务
const fs = require('fs'); // 第一种直接调用done exports.callback = done => { console.log('callback task'); done(); } exports.callback_error = done => { console.log('callback_error task'); done(new Error('callback_error task failed')); } // 第二种promise的方式 exports.promise = () =>{ console.log('promise task') return Promise.resolve() } const timeout = time =>{ return new Promise((resolve) => { setTimeout((resolve,time)) }) } exports.async = async ()=>{ await timeout(1000) console.log('async task') } // 第三种 添加实例方法,调用done exports.stream = () =>{ const readStream = fs.createReadStream('package.json') const writeStream = fs.createWriteStream('temp.txt') readStream.pipe(writeStream) // return readStream // 或者写成 readStream.on('end',()=>{ done() }) }
gulp构建过程核心工作原理
const fs = require('fs'); const { Transform } = require('stream'); exports.default = () =>{ // 创建文件读取流 const read = fs.createReadStream('normalize.css') // 文件写入流 const write = fs.createWriteStream('normalize.min.css') // 文件转换流 const transform = new Transform({ transform: (chunk,encoding,callback) => { // 核心转换过程 // chunk读取流中读取到的内容(Buffer),所以需要toString拿到文件内容 const input = chunk.toString() const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '') callback(null, output) } }) // 把读取出来的文件流导入写入文件流 read .pipe(transform) .pipe(write) return read }
Gulp文件操作API
读取流 — 转换流 — 写入流
const { src, dest } = require('gulp') const cleanCss = require('gulp-clean-css') // css的转换流 const rename = require('gulp-rename') exports.default = done =>{ // src读取流,dest写入流,return出去让gulp知道此任务已完成 return src('src/*.css') .pipe(cleanCss()) // 转换css .pipe(rename({ extname: '.min.css' })) .pipe(dest('dist')) }
Gulp转换项目的案例
// 实现这个项目的构建任务 // watch自动监听通配符,根据文件更新来决定是否要执行某个人物 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() //loadPlugins导出的是一个方法,通过方法得到plugins const bs = browserSync.create() // 用提供的creat()方法创建服务器 const data = { menus: [], pkg: require('./package.json'), date: new Date() } const clean = ()=>{ return del(['dist','temp']) } const page = ()=>{ // swig 为模板引擎的转换插件 // 原来的模板用到了一些数据标记,去标记开发中可能变化的东西 // 通过swig的data参数,把设定的data传入到模板中 return src('src/*.html', { base: 'src'}) .pipe(plugins.swig({ data })) .pipe(dest('temp')) .pipe(bs.reload({stream: true})) // 内部以流的方式推到浏览器, } const script = ()=>{ // gulp-babel只是帮你唤起@babel/core的转换过程 // preset-env会帮助转换所有的es6模块,他是可以转换所有新特性的集合 return src('src/assets/scripts/*.js', { base: 'src' }) .pipe(plugins.babel({presets: ['@babel/preset-env']})) .pipe(dest('temp')) .pipe(bs.reload({stream: true})) // 内部以流的方式推到浏览器, } const style = ()=>{ // outputStyle: 'expanded' 是指定转换后结束括号的位置 return src('src/assets/styles/*.scss', { base: 'src' }) .pipe(plugins.sass({ outputStyle: 'expanded'})) .pipe(dest('temp')) .pipe(bs.reload({stream: true})) // 内部以流的方式推到浏览器, } const image = ()=>{ // imagemin插件用于图片的压缩 return src('src/assets/images/**', { base: 'src'}) .pipe(plugins.imagemin()) .pipe(dest('dist')) } const font = ()=>{ // imagemin可以压缩字体文件中的svg 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的变化 watch('src/*.html',page) watch('src/assets/scripts/*.js',script) watch('src/assets/styles/*.scss',style) // 只是去监听iamge,font,public文件的变化,不去构建 watch([ 'src/assets/images/**', 'src/assets/fonts/**', 'public/**' ],bs.reload) // 初始化服务器配置 bs.init({ port: '2080', // 服务器端口号 // browser-sync 启动后用来去监听的路径通配符 // files:'temp/**', server: { // 请求过来后先从[0]目录下面去找,如果找不到就去src下面查找... baseDir: ['temp','src','public'], // 优先于baseDir的配置 routes: { '/node_modules': 'node_modules' } } }) } const useref = () =>{ // useref 自动处理构建注释 return src('temp/*.html', {base: 'temp'}) .pipe(plugins.useref({ searchPath: ['temp', '.'] })) // 希望对生成的文件进行压缩,因为读取流中有三个不同的文件,希望对不同文件进行不同操作 .pipe(plugins.if(/\.js$/, plugins.uglify())) .pipe(plugins.if(/\.css$/, plugins.cleanCss())) // 可以在方法中配置一些自定义的选项,下面的选项是压缩空白字符,压缩行内css,压缩w文件内js .pipe(plugins.if(/\.html$/, plugins.htmlmin({ collapseWhitespace: true, minifyCSS: true, minifyJS: true }))) .pipe(dest('dist')) } // 使用parallel把这些任务通过并行的方式导出 const compile = parallel(page,script,style ) // 一般 iamge,font public 的任务,项目开发阶段不会让他自动化构建,只是再发布的时候去构建项目 const build = series( clean, parallel( series(compile,useref), image, font, extra ) ) const start = series(compile, serve) module.exports = { build, start, clean }