Gulp入门学习笔记

Gulp是基于流的自动化构建工具,它不仅能对网站资源进行优化,而且在开发过程中能避免很多重复的工作,比如对相关文件的操作,还有自动监视一些文件的变化等功能。

基本的常用API(gulp v3.X)

  • gulp.src(globs[, options])

    输出符合所提供的匹配模式或者匹配模式的数组的文件。 将返回一个stream文件流它可以被 piped 到别的插件中。
    glob 相当于文件的路径,或者文件路径数组。

  • gulp.dest(path[, options])
    // 把上一步处理的数据输出到指定的目录path中,如果某文件夹不存在,将会自动创建它。

  • gulp.task(name[, deps], fn)

    例子:

    gulp.task('mytask', ['array', 'of', 'task', 'names'], function() {
         // 做一些事
    });
    

异步、同步、规定执行顺序执行任务

  • 异步执行任务

    const gulp = require('gulp');    
    // 压缩js代码
        gulp.task('js', function () {
            return gulp.src('src/js/*.js')   // 匹配参数内的文件,并且将文件读到gulp内存中
                .pipe(concat('bundle.js'))   // 合并文件代码
                .pipe(gulp.dest('dist/js/'))   // 输出文件到指定目录
                .pipe(uglify())    // 压缩当前的js文件
                .pipe(rename({      // 重命名文件
                    suffix: '.min'
                }))
                .pipe(gulp.dest('dist/js/'))
        })
    
    // 压缩css代码
    gulp.task('css', function () {
        return gulp.src('src/css/*.css')
            .pipe(concat('bundle.css'))
            .pipe(cleanCss())   // 压缩css文件
            .pipe(gulp.dest('dist/css/'))
    })
    
    // 执行数组内的任务
    gulp.task('default', ['js', 'css'])
    
当运行命令 gulp 后,我们发现输出的是
    [11:31:43] Using gulpfile E:\练习\Gulp\4-12\gulpfile.js
    [11:31:43] Starting 'css'...
    [11:31:43] Starting 'js'...
    [11:31:44] Finished 'js' after 72 ms
    [11:31:44] Finished 'css' after 70 ms
    [11:31:44] Finished 'default' after 33 μs
可以看到此时的任务是异步执行的,应用官方的一句话就是

默认的,task 将以最大的并发数执行,也就是说,gulp 会一次性运行所有的 task 并且不做任何等待。

但是如果我们想要它同步执行任务呢?应该怎么做?看代码
  • 同步执行任务
    const gulp = require('gulp');
    // 压缩css代码
    gulp.task('css', function () {
        gulp.src('src/css/*.css')
            .pipe(concat('bundle.css'))
            .pipe(cleanCss())   // 压缩css文件
            .pipe(gulp.dest('dist/css/'))
    })
    // 解析less代码并且压缩css代码
    gulp.task('less', function () {
        gulp.src('src/less/*.less')
            .pipe(concat('bundle_less.less'))
            .pipe(less())
            .pipe(cleanCss())
            .pipe(rename({
                suffix: '.min'
            }))
            .pipe(gulp.dest('dist/less'))
    })
    // 执行数组内的任务
    gulp.task('default', ['js', 'css'], 'less')

输出结果

[11:44:22] Using gulpfile E:\练习\Gulp\4-12\gulpfile.js
[11:44:22] Starting 'css'...
[11:44:22] Finished 'css' after 7.24 ms
[11:44:22] Starting 'less'...
[11:44:22] Finished 'less' after 3.01 ms
[11:44:22] Starting 'default'...
[11:44:22] Finished 'default' after 35 μs

可以看到,我们只需要把return去掉即可实现同步进行编译输出,也就是说,在task中只要不返回任何值即可实现同步执行任务

如果想特定安排任务的执行顺序呢?(同步异步都执行)

  • 按规定顺序执行任务
    const gulp = require('gulp');
    // 返回一个 callback,因此系统可以知道它什么时候完成
    gulp.task('one', function(cb) {
        // 做一些事 -- 异步的或者其他的
        cb(err); // 如果 err 不是 null 或 undefined,则会停止执行,且注意,这样代表执行失败了
    });
    // 定义一个所依赖的 task 必须在这个 task 执行之前完成
    gulp.task('two', ['one'], function() {
        // 'one' 完成后
    });
    gulp.task('default', ['one', 'two']);

解析:运行时,gulp会执行task one,当执行该函数的回调时候,如果 err 不是 null 或 undefined,则会停止执行,且注意,这样代表执行失败了,如果没有发生错误,那么才回去执行task two。也就是说,任务two必须在任务one的后面执行

了解常用插件

  • gulp-concat 合并文件,减少网络请求。基本使用方法:
        const gulp   = require('gulp'),
        concat = require('gulp-concat'),
        pump   = require('pump');
        gulp.task('testConcat', function (cb) {
            pump([
                gulp.src('src/js/*.js'),
                concat('all.js'),//合并后的文件名
                gulp.dest('dist/js')
            ], cb);
        });
    
  • gulp-uglify 压缩js文件,减少文件体积,去掉没有引用的代码。基本使用方法:
        gulp.task('jsmin',function(){
        gulp.src(['src/js/index.js','src/js/detail.js'])//多个文件以数组形式传入
            .pipe(uglify({
                //mangle: true,//类型:Boolean 默认:true 是否修改变量名
                mangle:{except:['require','exports','module','$']},//排除混淆关键字
                compress:true,//类型:Boolean 默认:true 是否完全压缩
                preserveComments:'all'//保留所有注释
            }))
            .pipe(gulp.dest('dist/js'))
        });
    
  • gulp-rename 修改文件名,例如将demo.css修改为demo.min.css,一般配合gulp-minify-css/gulp-uglify压缩插件一起使用。基本使用方法(修改输出的js文件名):
        gulp.task('renamejs',function(){
            return pump([
                gulp.src('src/js/*.js'),
                rename({suffix: '.min'}),   // 输出文件名修改为带.min的文件名
                uglify(),
                gulp.dest('dist/js')
            ])
        })
    
  • gulp-clean-css 使用gulp-clean-css压缩css文件,减小文件大小,并给引用url添加版本号避免缓存。(之前的有同样功能的gulp-minify-css已被废弃)。基本使用方法:
        gulp.task('testCssmin', function () {
            gulp.src('src/css/*.css')
                .pipe(cssmin({
                    advanced: false, //类型:Boolean 默认:true [是否开启高级优化(合并选择器等)]
                    compatibility: 'ie7', //保留ie7及以下兼容写法 类型:String 默认:''or'*' [启用兼容模式; 'ie7':IE7兼容模式,'ie8':IE8兼容模式,'*':IE9+兼容模式]
                    keepBreaks: true, //类型:Boolean 默认:false [是否保留换行]
                    keepSpecialComments: '*'  //保留所有特殊前缀 当你用autoprefixer生成的浏览器前缀,如果不加这个参数,有可能将会删除你的部分前缀
                }))
                .pipe(gulp.dest('dist/css'));
        });
    
  • gulp-less 使用gulp-less插件将less文件编译成css,当有less文件发生改变自动编译less,并保证less语法错误或出现异常时能正常工作并提示错误信息。基本使用方法:
        gulp.task('testLess', function () {
            gulp.src('src/less/index.less')
                .pipe(less())   // 解析less文件转换为css
                .pipe(gulp.dest('src/css'));
        });
    
  • gulp-htmlmin 使用gulp-htmlmin压缩html,可以压缩页面javascript、css,去除页面空格、注释,删除多余属性等操作。基本使用方法:
        const htmlMin = require('gulp-htmlmin');
        gulp.task('testHtmlmin', function () {
            gulp.src('src/html/*.html')
                .pipe(htmlMin({
                    removeComments: true,//清除HTML注释
                    collapseWhitespace: true,//压缩HTML
                    collapseBooleanAttributes: true,//省略布尔属性的值 <input checked="true"/> ==> <input />
                    removeEmptyAttributes: true,//删除所有空格作属性值 <input id="" /> ==> <input />
                    removeScriptTypeAttributes: true,//删除<script>的type="text/javascript"
                    removeStyleLinkTypeAttributes: true,//删除<style>和<link>的type="text/css"
                    minifyJS: true,//压缩页面JS
                    minifyCSS: true//压缩页面CSS
                }))   // 解析html文件并且压缩
                .pipe(gulp.dest('dist/html'));
        });
    
  • gulp-livereload 实现项目自动编译(半自动,页面不会刷新)。基本使用方法:
        const livereload = require('gulp-livereload');
        gulp.task('testLess', function () {
            gulp.src('src/less/index.less')
                .pipe(less())   // 解析less文件转换为css
                .pipe(gulp.dest('src/css'))
                .pipe(livereload())
        });
        // 这里要先让默认任务执行一遍后
        gulp.task('watch', ['default'], function () {
            // 开启监听
            livereload.listen();
            // 确认监听的目标文件和对应所执行的task
            gulp.watch('src/less/*.less', ['testLess']);
            gulp.watch('src/html/*.html', ['minHtml']);
        })
    
  • gulp-connect 实现实时编译和浏览器自动刷新(全自动)。基本使用方法:
        const connect = require('gulp-connect');
        gulp.task('css', function () {
            return pump([
                gulp.src('src/css/*.css'),
                concat('bundle.css'),
                cleanCss(),
                rename({
                    suffix: '.min'
                }),
                gulp.dest('dist/css/'),
                connect.reload()   // 这一句实现修改后会刷新
            ])
        })
        gulp.task('server', ['default'], function () {
            connect.server({
                root: 'dist/',   // 编译后对应映射到哪个文件目录下
                port: 8080,   // 端口号
                livereload: true   // 使用自动编译
            });
            gulp.watch('src/css/*.css', ['css']);
            gulp.watch('src/html/*.html', ['minHtml']);
        })
    
  • gulp-autoprefixer 实现版本自动添加前缀。基本使用方法:
        const autoprefixer = require('gulp-autoprefixer')
        /*自动加前缀*/
        gulp.task('autoprefixer', function () {
            return gulp.src('css/*.css')
                .pipe(autoprefixer({
                    browsers: ["last 2 versions","Firefox >= 20"],
                    /*last 2 versions: 主流浏览器的最新两个版本
                    ● last 1 Chrome versions: 谷歌浏览器的最新版本
                    ● last 2 Explorer versions: IE的最新两个版本
                    ● last 3 Safari versions: 苹果浏览器最新三个版本
                    ● Firefox >= 20: 火狐浏览器的版本大于或等于20
                    ● iOS 7: IOS7版本
                    ● Firefox ESR: 最新ESR版本的火狐
                    ● > 5%: 全球统计有超过5%的使用率
                    */
                    cascade: true, //是否美化属性值 默认:true 像这样:
                    //-webkit-trans==>m: rotate(45deg);
                    //        trans==>m: rotate(45deg);
                    remove:true //是否去掉不必要的前缀 默认:true 
                }))
                .pipe(gulp.dest('css/'));
        });
    
  • gulp-load-plugins 所有的gulp插件都存在这里面。基本使用方法:
        // 必须要先调用一下这个函数才能使用
        const $ = require('gulp-load-plugins')();
        // 此时, 这些不在需要引入
        const concat = require('gulp-concat');
        const uglify = require('gulp-uglify');
        const rename = require('gulp-rename');
        const cleanCss = require('gulp-clean-css');
        ...
        // 使用下面的写法代替上面的插件
        $.concat
        $.uglify
        $.rename
        $.cleanCss
        $.htmlmin
        ...
    
  • gulp-babel 编译ES6、7转换为ES5。基本使用方法:
        const babel = require('gulp-babel');
        gulp.task('es', function () {
            return gulp.src('src/js_es6/*.js')
                .pipe(babel({                   // 编译es6语法
                    presets: ["@babel/env"],
                    plugins: []
                }))
                .pipe(concat('bundle.js'))
                .pipe(gulp.dest('dist/'))
        })
        
        gulp.task('default', gulp.series(['es']))
        
        // 依赖版本
        // "@babel/core": "^7.4.3",
        // "@babel/preset-env": "^7.4.3",
        // "gulp": "^4.0.0",
        // "gulp-babel": "^8.0.0",
    

Gulp4.0升级了什么

  • gulpgulp.task()中移除了三参数语法,现在不能使用数组来指定一个任务的依赖。gulp 4.0 加入了 gulp.series 和 gulp.parallel 来实现任务的串行化和并行化。

    gulp.series 用于串行(顺序)执行

        gulp.task('default', gulp.series(['html', 'css', 'js']))
    

    gulp.parallel 用于并行执行,如果你想并行执行scripts和styles,你可以这么写:

        gulp.task('default', gulp.parallel('scripts', 'styles'));
    

    通常gulp.series 和 gulp.parallel我们需要配合来使用。

  • 依赖陷阱

    让我们看一下这个Gulp3的例子:

        // default任务,需要依赖scripts和styles
        gulp.task('default', ['scripts', 'styles'], function() {});
        // script和styles任务都依赖clean
        gulp.task('styles', ['clean'], function() {});
        gulp.task('scripts', ['clean'], function() {});
        // clean任务用来清空目录
        gulp.task('clean', function() {});
    

    当Gulp开始工作,它会创建一个任务依赖树

    它发现clean任务是另外两个task的依赖,从而确保clean只执行一次。

    但遗憾的是,我们在新版本中将没办法运用这个特性。如果你在迁移到Gulp4的过程中只像下面的例子一样做了简单的改变,clean任务将会被执行两次:

        // 任务直接不再有依赖
        gulp.task('styles', function() {...});
        gulp.task('scripts', function() {...});
        gulp.task('clean', function() {...});
        
        // default任务,需要依赖scripts和styles
        gulp.task('default', gulp.series('clean', gulp.parallel('scripts', 'styles')));
    
  • 异步任务支持

    如果你执行的是同步任务,在Gulp3中不需要写任何其他代码,但是在Gulp4中就不能如此轻松了:现在也你必须运行done回调(这可能是我最早发现的一个变化)。然后如果你执行的是异步任务,你则有三个选择来确保Gulp能够检测到你的任务真的完成了:

    • 回调
        const del = require('del');
        // del 模块用来删除指定目录的文件
        gulp.task('clean', function(done) {
            del(['.build/'], done);
        });
    

    • 返回一个流告诉gulp任务你已经处理完成
          gulp.task('somename', function() {
              return gulp.src('client/**/*.js')
                  .pipe(minify())
                  .pipe(gulp.dest('build'));
          });
      
    • Promise
      返回一个Promise来告诉gulp任务已经处理完成
          var promisedDel = require('promised-del');
          gulp.task('clean', function() {
              return promisedDel(['.build/']);
          });
      
  • 使用函数定义任务

    具体使用方法:

        // 只需要在`series` 和 `parallel` 中间引用函数名就能组成一个新任务
        gulp.task('default', gulp.series(clean, gulp.parallel(scripts, styles)));
        
        // 把单个任务变成一个函数
        function styles() {}
        function scripts() {}
        function clean() {}
    

    此处参考了:
    【译】相对完整的Gulp4升级指南
    Gulp 4: gulp.parallel gulp.series -- 全新的任务执行体系

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容