gulp使用

215 阅读4分钟

最简单的案例

安装:

npm install --g gulp-cli

npm install --save-dev gulp

注册任务并执行

项目根目录下需要有gulpfile.js作为配置文件,执行gulp命令时后面需要加上任务名,这个任务名是在gulpfile.js配置文件中挂在exports上的方法,例如:

function callbackTask(done) {
	setTimeout(() => {
  	console.log('callbackTask')
    done()
  }, 1000)
}
exports.callback = callbackTask

在命令行执行gulp callback即可

gulp中只有异步任务,同步任务已经被废弃

各种异步任务类型:

const fs = require('fs');
const through = require('through2');

function callbackTask(done) {
    setTimeout(() => {
        console.log('callbackTask');
        done();//调用done方法就表示任务完成了
    }, 1000);
}
function promiseTask() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('promiseTask');
            resolve();//调用resolve方法就表示promise成功了
        }, 1000);
    });
}
async function asyncTask() {
    await new Promise(resolve => {
        setTimeout(() => {
            console.log('asyncTask');
            resolve();//调用resolve方法就表示promise成功了
        }, 1000);
    });
}
function streamTask() {
    //流的操作其实也是异步的,这个任务也需要等待流这个异步任务之后才会让任务结束
    let rs = fs.createReadStream('input.txt', { autoClose: true });
    let ws = fs.createWriteStream('output.txt', { autoClose: true });
    return rs.pipe(through((chunk, enc, next) => {
        setTimeout(() => {
            next(null, chunk.toString() + "$");
        }, 1000);
    })).pipe(ws, { end: true }).on('end', () => console.log('end'));
}

exports.callback = callbackTask;
exports.promise = promiseTask;
exports.async = asyncTask;
exports.stream = streamTask;

命令行分别执行gulp callback/gulp promise/gulp async/gulp stream即可触发对应任务

gulp还可以注册组合任务,来完成异步串行、异步并行的操作

const fs = require('fs');
const through = require('through2');
const { series, parallel } = require('gulp');
function callbackTask(done) {
    ...
}
function promiseTask() {
    ...
}
async function asyncTask() {
    ...
}
function streamTask() {
    ...
}
// parallel类似Promise.all,实现异步并行
const parallelTask = parallel(callbackTask, promiseTask, asyncTask, streamTask);
// parallel类似Promise.all,实现异步串行
const seriesTask = series(callbackTask, promiseTask, asyncTask, streamTask);

exports.callback = callbackTask;
exports.promise = promiseTask;
exports.async = asyncTask;
exports.stream = streamTask;
exports.parallel = parallelTask;//Promise.all
exports.series = seriesTask;

文件拷贝任务:

const { src, dest } = require('gulp');
function copyTask() {
	console.log('执行拷贝文件');
  return src('src/scripts/**/*.js').pipe(dest('dist'))
}
export.copy = copyTask

注:

dest指定的是输出的目录名,不包括文件路径

文件路径或者说文件名是glob里通配符开始的路径部分,此处就是src/scripts//*.js中/*.js对应的部分

本案例中src/scripts下有main.js这个文件,所以在进程执行的目录下会生成dist,将打包后的文件放到这个目录下

如果想要自定义打包后的目录,可以指定base属性,例如:

src('src/scripts/**/*.js', { base: 'src' }).pipe(dest('dist'))

就可以将src作为基准目录,src后面的scripts也会成为打包后的目录,打包后的目录中将会包含scripts

以此来推测,gulp打包后的目标文件和源文件的目录结构是非常像的

注:

出于某些包的实现方式的原因,如果需要使用esm模块规范,则需要通过import动态引入来实现,例如压缩图片的任务就是这样:

const images = async () => {
    const imagemin = await import('gulp-imagemin');
    return src("src/assets/images/**/*.@(jpg|png|gif|svg)", { base: 'src' })
        .pipe(imagemin.default())
        .pipe(dest('dist'))
}
exports.images = images;

各种任务:

const { src, dest, parallel, watch, series } = require('gulp');
const plugins = require('gulp-load-plugins')();
const browserSync = require('browser-sync');
const browserServer = browserSync.create();
//清除输出目录
const clean = () => {
    return src(["dist/**", "temp/**"], { read: false })
        .pipe(plugins.clean())
}
//编译样式
const styles = () => {
    return src("src/styles/**/*.less", { base: 'src' })
        .pipe(plugins.less())
        .pipe(dest('temp'))
}
//编译JS脚本
const scripts = () => {
    return src("src/scripts/**/*.js", { base: 'src' })
        .pipe(plugins.babel({
            presets: ["@babel/preset-env"]
        }))
        .pipe(dest('temp'))
}
//编译html模板
const html = () => {
    return src("src/**/*.html", { base: 'src' })
        .pipe(plugins.ejs({ "title": 'gulp实战' }, { cache: false }))
        .pipe(dest('temp'))
}
//压缩图片
const images = async () => {
    const imagemin = await import('gulp-imagemin');
    return src("src/assets/images/**/*.@(jpg|png|gif|svg)", { base: 'src' })
        //.pipe(imagemin.default())
        .pipe(dest('dist'))
}

//拷贝不需要任务编译 处理的静态文件,到输出目录
const static = () => {
    return src("static/**", { base: 'static' })
        .pipe(dest('dist'))
}
const serve = () => {
    watch('src/styles/**/*.less', styles).on('change', browserSync.reload);;
    watch('src/scripts/**/*.js', scripts).on('change', browserSync.reload);;
    watch('src/**/*.html', html).on('change', browserSync.reload);;
    watch([
        "src/assets/images/**/*.@(jpg|png|gif|svg)",
        "static/**"
    ], browserServer.reload);
    //serve和webpack-dev-server里的打包不一样,serve不会在内存和硬盘上生成任何文件,
    //webpack-dev-server也只读内存中的文件,webpack打包生成到内存里,
    return browserServer.init({
        notify: false,
        server: {
            baseDir: ['temp', "src", "static"],//静态文件根目录
            files: ['dist/**'],//监听 文件变化,文件变化后重新刷新浏览器
            routes: {
                '/node_modules': 'node_modules'
            }
        }
    });
}
const concat = () => {
    //src index.html
    //经过useref处理之后变成 里面有三个文件了index.html build.css build.js
    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(styles, scripts, html);
const build = series(clean, parallel(series(compile, concat), images, static));
const dev = series(clean, compile, serve);
//生成环境构建
exports.build = build;
//开发环境预览
exports.dev = dev;

///assets/images/circle.svg
//  dist/assets/images/circle.svg
// src/assets/images/circle.svg

///rect.svg

//dist/rect.svg
// src/rect.svg
// static/rect.svg