一文学会gulp

说一下前端的自动化构建工具gulp吧,其实国内的前端自动化工具比较流行的还有就是fisgrunt了,但是我觉得目前gulp的社区相对友好,而且关于gulp也是特别容易快速上手的

请一定要看我贴的代码,因为许多的gulp知识我都是通过粘贴代码附带对应的注释的方式讲解的,这样的话你不懂代码就在下边可以结合注释讲解快速入门gulp的

那么首先我们先进行全局安装gulp

npm i -g gulp

然后我们需要在我们需要构建的项目中局部安装一个本地开发依赖gulp

npm i -D gulp

然后我们需要新建一个用于执行gulp任务的js文件,默认为gulpfile.js文件
这也就是我们需要局部安装gulp的原因,因为我们的默认gulpfile文件中需要引用到gulp这个依赖,也就是

require("gulp")

如果package.json文件中没有的话不就出问题了吗?

那么其实所有的构建工具感觉上都是一样的,如果没有插件就没有任何的用处,所以这里我们需要接触到我们的第一个插件

npm install --save-dev gulp-uglify

然后我们在代码中这样写

const gulp = require("gulp")

// 命名的话一般就是去掉gulp等字符,因为在这个gulpfile中一看就知道是gulp的插件啊,总不可能是webpack的loader吧
// gulp-uglify这个插件代表着压缩js代码
const uglify = require("gulp-uglify")

// 建议大家使用es5函数,而不是箭头函数
// task函数可以声明一个gulp的task,那么默认gulp是以task进行工作的
// 每一部分的构建都可以细分不同的task
gulp.task("minify",function(){
    // 第一个参数为task的名字,尽量是一看名字就知道是干啥的那种
    // 这里是运行这个任务的逻辑
    
    

    // src函数,gulp是以数据流的方式进行构建我们的代码的
    // 所以我们需要使用src函数为gulp提供一个需要待处理的输入流数据
    gulp.src("./js/01.js")
    // 然后我们可以通过管道的方式让不同的插件处理这些数据
    .pipe(uglify())
    // 同样的我们需要通过管道将这些数据输出出去
    // 这里我们使用dest函数代表输出经过处理的src函数提供的数据流
    .pipe(gulp.dest("./01.min.js"));
})

那么我们的代码中引用了js文件夹下的所有js文件大家可以自行书写一些js文件,那么我这里是在js文件夹下01.js文件的内容是

function Person(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}
Person.prototype = {
    constructor: Person,
    sayHello:function() {
        console.log("name:" + this.name + "age:" + this.age + "sex:" + this.sex);
    }
}

new Person("suiyue",10,"男").sayHello();

然后现在是不是特别的激动呢?我们现在是万事俱备,只欠东风了,那么我们快速打开我们的cmd工具定位到当前目录下吧,然后我们运行

gulp taskname
// 这里我们
gulp minify

执行这个task吧,我们看看效果吧


效果

大家一定要注意啊,这个坑爹的uglify是不能够压缩es6js语法的,直接报错明白吧,刚开始写的是classclass`后面几次报错就改成原始写法了,贼坑,注意

然后我们就会发现我们的代码已经打包好了

打包好了

那么大家还会发现控制台报了一个错误,大致意思好像是说这个task没有完成,需要异步执行,这里就有两种解决办法了,我们可以直接给task后面的函数加上async关键字

image.png

完美解决,第二种就是可以给task后面的逻辑处理函数接受一个可选的done回调主动告诉gulp任务完成

image.png

同样的可以完美解决,但是还是建议大家使用async关键字,使用异步函数解决此问题,异步就是不可控性,其实你并不知道他什么时候就能够执行完成,所以有些时候根本不知道什么时候回调done函数,请大家选择第一种方式

关于第一个插件gulp-uglify就说到此,接下来说一说gulp上面的babel插件,不然的话高阶语法根本无法丑陋化,你懂我的意思吧

  • gulp-babel

关于gulp-babel就是gulp调用babel模块转换js语法而已,其实本质上是一样的,那么我们首先安装项目依赖,这里推荐大家使用babel7,所以直奔babel7了,而且babel7配置相对babel6要简单的多

npm install --save-dev gulp-babel @babel/core @babel/preset-env

然后我们立马给gulp下达一个任务吧,配置好任务

const gulp = require("gulp")
// 压缩js代码插件
const uglify = require("gulp-uglify")
// babel插件
const babel = require("gulp-babel")


// 压缩js代码任务
gulp.task("minify", async function () {
    gulp.src("./js/01.js")
        .pipe(uglify())
        .pipe(gulp.dest("./01.min.js"));
})


gulp.task("tfSyntax",async function(){
    gulp.src("js/*.js")
        .pipe(babel({
            // 相当于babel配置文件
            presets:["@babel/env"]
        }))
        .pipe(gulp.dest("dist"))
})

更改我们js的代码为高阶语法

class Person {
    constructor(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    sayHello() {
        console.log(`我叫${this.name}我今年${this.age}岁了我是一个小小小${this.sex}生`);
    }
}

new Person("suiyue",10,"男").sayHello();

好的,我们迅速在命令行中运行

gulp tfSyntax 

让gulp跑起来,不出意外的话,那么我们就会在dist目录下看到被转换后的代码,就像这样

"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

var Person =
/*#__PURE__*/
function () {
  function Person(name, age, sex) {
    _classCallCheck(this, Person);

    this.name = name;
    this.age = age;
    this.sex = sex;
  }

  _createClass(Person, [{
    key: "sayHello",
    value: function sayHello() {
      console.log("\u6211\u53EB".concat(this.name, "\u6211\u4ECA\u5E74").concat(this.age, "\u5C81\u4E86\u6211\u662F\u4E00\u4E2A\u5C0F\u5C0F\u5C0F").concat(this.sex, "\u751F"));
    }
  }]);

  return Person;
}();

new Person("suiyue", 10, "男").sayHello();

这时候相信学到这里你就有点懵圈了,不是说好的自动化工具吗?我怎么感觉我转换了高阶语法还要在gulp一下minify这个task才能行呢?自动化不是应该什么都帮我们做了吗?这是一个什么鬼情况?

在这里我想说的就是大家莫要慌,我们接着往下读

然后我们说一下gulp的默认任务,我们现在是个什么情况,我们现在就是每一次声明一个任务然后就必须在控制台中gulp一下任务名称运行,那么作为自动化工具的gulp当然不会这么low,你懂吧?所以gulp提供了一个默认的任务让我们直接运行gulp就行了,请看下面

const gulp = require("gulp")
// 压缩js代码插件
const uglify = require("gulp-uglify")
// babel插件
const babel = require("gulp-babel")


// 这是一个坑爹的默认任务名,还要手打
gulp.task("default",async function(){
    // 如果直接在命令行敲gulp,就会默认运行 default这个任务,没有就没有咯
    console.log("123");
})


// 压缩js代码任务
gulp.task("minify", async function () {
    gulp.src("./js/01.js")
        .pipe(uglify())
        .pipe(gulp.dest("./01.min.js"));
})

// 转换高阶语法任务
gulp.task("tfSyntax",async function(){
    gulp.src("js/*.js")
        .pipe(babel({
            // 相当于babel配置文件
            presets:["@babel/env"]
        }))
        .pipe(gulp.dest("dist"))
})

那么我们这里在default任务中输出123,那么我们直接在命令行中

gulp

直接gulp就行了,这样就输出了123,大家应该懂了什么叫做默认任务了吧!

然后我们就可以进行先转换代码再压缩代码的功能了

const gulp = require("gulp")
// 压缩js代码插件
const uglify = require("gulp-uglify")
// babel插件
const babel = require("gulp-babel")


gulp.task("minifyJS",async ()=>{
    gulp.src("js/*.js")
        .pipe(babel({
            presets:['@babel/env']
        }))
        .pipe(uglify())
        .pipe(gulp.dest("dist"))
})

大家应该能够看懂代码了吧


cmd

大家就可以在对应的dist文件夹下看到我们转换压缩之后的js代码了

但是到这时候我们还是没有体会到gulp的自动化啊,因为我们一整个项目不仅需要处理js还有css也可能需要处理html啊,到这时候我们还是没有发现gulp哪里自动化了,继续继续继续

  • 任务的依赖

顺序执行

关于gulp任务的依赖,就是实现自动化的最大一特性,配合gulp的默认task可以迅速实现gulp的自动化

这里主要说说gulp最新版本gulp4的任务依赖,gulp3跟gulp改动还是稍微有点大的,还有就是目前(2019年7月13日-11点16分)gulp中文网的文档还是gulp3的但是我们现在安装的gulp已经默认为gulp4了,同时也推荐大家使用gulp4,因为gulp4对比gulp3优化了很多东西

然后这里我从头开始写一个gulpfile出来

const gulp = require("gulp")

gulp.task("one",function(done){
    console.log("one")
    done()
})


gulp.task("two",function(done){
    console.log("two")
    done()
})

// 第一点就是这个默认的default任务一定要写在最下边,不然后面的series任务不会被找到
gulp.task("default",gulp.series("one","two",function(done){
    // series函数可以传递一系列的任务进去被顺序执行(顺序,不是并行的)
    // 所以会出现先执行前面一个再执行后面一个,然后因为这是顺序执行的所以我们可以将default任务的处理函数放在最后
    // 但是大家要明白series函数接收的是一个个任务,这就意味着一个函数也可以成为一个任务,我们后面添加一个three试试
    console.log("done")
}))
done

这里的报错因为没有调用done并且还不是异步函数,所以出错了

const gulp = require("gulp")

gulp.task("one",function(done){
    console.log("one")
    done()
})


gulp.task("two",function(done){
    console.log("two")
    done()
})

// 这里可以直接通过task方法将这个函数转换为对应的任务
async function three(done){
    console.log(three);
}
gulp.task(three);


gulp.task("default",gulp.series("one","two","three",async function(){
    console.log("done")
}))

并行执行

然后我这里写了这些代码

const gulp = require("gulp")

gulp.task("one",async function(){
    let i = 0;
    while(i<10000){
        i++;
    }
    console.log("one执行完成");
})


gulp.task("two",async function(){
    let i = 0;
    while(i<10000){
        i++;
    }
    console.log("two执行完成");
})

// 这里可以直接通过task方法将这个函数转换为对应的任务
async function three(done){
    let i = 0;
    while(i<10000){
        i++;
    }
    console.log("three执行完成");
}
gulp.task(three);


// parallel函数跟series函数差不多,只不过里面的任务会并行执行
gulp.task("default",gulp.parallel("one","two","three",async function(){
    let i = 0;
    while(i<10000){
        i++;
    }
    console.log("这是并行执行的,我不一定是最后一个输出了");
}))

你明白吧,我就可以直接在控制台中查看一下情况


并行

这真的是并行执行的,你没发现一次性开始了所有的任务又然后中间输出又完成所有的任务了吗?看看series的控制台情况吧


对比

对比一下就知道这是并行执行的了

嵌套

这是gulp的一个超级大亮点,就是并行和顺序任务可进行过互相嵌套,并行可以嵌套在顺序中,顺序可以嵌套在并行中

const gulp = require("gulp")

gulp.task("one",async function(){
    console.log("我第一");
})


gulp.task("two",async function(){
    console.log("我第二");
})

// 这里可以直接通过task方法将这个函数转换为对应的任务
async function three(done){
    console.log("我第三");
}
gulp.task(three);


// 这就代表着会优先并行执行one,two等待这两个task结束后,在顺序执行three和最后的回调函数
gulp.task("default",gulp.series(gulp.parallel("one","two"),"three",async function(){
    console.log("我最后");
}))

可以互相嵌套,灵活运用哦


image.png
  • watch

自动化怎么可能少得了监听呢?一个监听使用的小小例子

const gulp = require("gulp")

gulp.task("watch",async function(){
    // 指定监听的文件
    gulp.watch("js/*.js",done=>{
        // 可以指定一个具体的回调函数,或者指定一个或多个任务进行处理
        console.log("修改了js文件");
        done();
    })
})

也可以使用绑定事件监听的方式完成文件的监听

const gulp = require("gulp")

const watcher = gulp.watch("js/*.js");

gulp.task("watch",async function(){
//每一个监听具体什么作用大家自己可以测试一下
    watcher.on("change",(path,stats)=>{
        console.log(path,stats);
    })
    watcher.on("add",(path,stats)=>{
        console.log(path,stats);
    })
    watcher.on("unlink",(path,stats)=>{
        console.log(path,stats);
    })
})

常用插件

前面说了gulp的两个插件了,分别是gulp-uglify,gulp-babel,这两个插件可以说是在构建中非常常用的,特别是Babel了,接下来说一说其他的插件吧

  • gulp-less

那么由于我主要用的是less作为常用css预处理器,大家可能会有用scss,stylus等等的,其实gulp也有对应的插件,大家可以去npm上搜索或者百度

npm i -D gulp-less

我们首先安装这个插件,然后我们可以在同级目录下新建一个css文件夹在下边创建一个less文件,其实gulp跟webpack还是有所不同的,因为gulp不像webpack那样通过一个入口文件开始整合资源代码那样,gulp直接可以定义任务然后自动执行就行了

@color:red;
body{
color: @color;
}

我就这样简单的写一下less文件了,然后我们快速的给gulp文件定义一个处理less的任务吧

const gulp = require("gulp")
const uglify = require("gulp-uglify")
const babel = require("gulp-babel")
const less = require("gulp-less")

// 任务名就是函数的名字
gulp.task(async function minifyJS() {
    // []表示匹配多个源,!就是正则表达式的非 的->意思
    gulp.src(["js/*.js", "!js/*.min.js"])
        .pipe(babel({
            presets: ["@babel/env"]
        }))
        .pipe(uglify())
        .pipe(gulp.dest("dist/js"))
})

gulp.task(async function tfLess() {
    gulp.src("css/*.less")
        .pipe(less())
        .pipe(gulp.dest("dist/css"))
})

// 默认任务
gulp.task("default", gulp.parallel(
    "minifyJS","tfLess"
));

然后我们这里就迅速的写了两个task,通过default并发执行两个task,因为这两个task的执行并不会互相冲突,然后我们就可以在命令行运行gulp看看了

body {
  color: red;
}

那么这就是我转换之后的css文件了,你会发现为什么这个css文件有点不大对劲,对!其实就是没有进行压缩啊

  • gulp-clean-css

压缩css代码在gulp中我们可以使用这个插件完成,那么我看了一下这个插件的下载量还是有点客观的,就没有使用另一款插件了(gulp-csso)

npm install gulp-clean-css --save-dev

那么我们安装完成这个插件之后怎么用呢,其实就是继续在刚刚那个处理less的流基础上再让这个插件处理一下就行了

const gulp = require("gulp")
const uglify = require("gulp-uglify")
const babel = require("gulp-babel")
const less = require("gulp-less")
const cleanCSS = require("gulp-clean-css")


// 任务名就是函数的名字
gulp.task(async function minifyJS() {
    // []表示匹配多个源,!就是正则表达式的非 的->意思
    gulp.src(["js/*.js", "!js/*.min.js"])
        .pipe(babel({
            presets: ["@babel/env"]
        }))
        .pipe(uglify())
        .pipe(gulp.dest("dist/js"))
})

gulp.task(async function tfLess() {
    gulp.src("css/*.less")
        .pipe(less())
        .pipe(cleanCSS({compatibility: 'ie8'}))
        .pipe(gulp.dest("dist/css"))
})

// 默认任务
gulp.task("default", gulp.parallel(
    "minifyJS","tfLess"
));

那么这下打包之后大家再看一下自己的css文件就发现已经完全的minify了,那么关于这个插件,介绍是说这个插件是clean-css在gulp上的实现,其实就是包装了一下clean-css,所以这个插件可以使用clean-css 的API,那么上面用到的compatibility(兼容性)选项就是clean-css的,关于clean-css 的更多信息传送
(周下载超500w次,你明白吧)

那么介绍一些其他的插件吧

  • gulp-concat

顾名思义就是用来连接多个文件的
这里我们可以在js文件夹中新建一个02.js文件

for(let i=0;i<1000;i++){
    console.log(i);
}

let j = 0;
while(j<10000){
    j++;
}

console.log("done");

为了节省时间就随便写了几行代码,然后我们快速安装使用下吧

npm install --save-dev gulp-concat
const gulp = require("gulp")
const uglify = require("gulp-uglify")
const babel = require("gulp-babel")
const less = require("gulp-less")
const cleanCSS = require("gulp-clean-css")
const concat = require("gulp-concat")


// 任务名就是函数的名字
gulp.task(async function minifyJS() {
    // []表示匹配多个源,!就是正则表达式的非 的->意思
    gulp.src(["js/*.js", "!js/*.min.js"])
        .pipe(babel({
            presets: ["@babel/env"]
        }))
        // 在压缩之前合并js文件
        // 需要换入合并之后的文件名
        .pipe(concat("all.js"))
        .pipe(uglify())
        .pipe(gulp.dest("dist/js"))
})

gulp.task(async function tfLess() {
    gulp.src("css/*.less")
        .pipe(less())
        .pipe(cleanCSS({compatibility: 'ie8'}))
        .pipe(gulp.dest("dist/css"))
})

// 默认任务
gulp.task("default", gulp.parallel(
    "minifyJS","tfLess"
));

你就会发现合并竟然是如此的简单,你以为这样就结束了,不你错了,它不仅可以合并js文件同样也可以合并css文件,你明白吧,只需要修改对应的css文件处理任务函数

    gulp.task(async function tfLess() {
        gulp.src("css/*.less")
            .pipe(less())
            .pipe(concat("index.css"))
            .pipe(cleanCSS({compatibility: 'ie8'}))
            .pipe(gulp.dest("dist/css"))
    })
  • gulp-rename

这个东西顾名思义,我们肯定需要将打包后的js或者css文件改成min格式的吧,所以就需要使用这个工具了

npm i -D gulp-rename
const gulp = require("gulp")
const uglify = require("gulp-uglify")
const babel = require("gulp-babel")
const less = require("gulp-less")
const cleanCSS = require("gulp-clean-css")
const concat = require("gulp-concat")
const rename = require("gulp-rename")


// 任务名就是函数的名字
gulp.task(async function minifyJS() {
    // []表示匹配多个源,!就是正则表达式的非 的->意思
    gulp.src(["js/*.js", "!js/*.min.js"])
        .pipe(babel({
            presets: ["@babel/env"]
        }))
        // 在压缩之前合并js文件
        // 需要换入合并之后的文件名
        .pipe(concat("all.js"))
        .pipe(uglify())
        .pipe(rename(path => {
            // 这里我们只需要修改basename属性即可
            // 若需要查看有哪些可修改属性请
            // console.log(path)

            path.basename += "-min";
        }))
        .pipe(gulp.dest("dist/js"))
})

gulp.task(async function tfLess() {
    gulp.src("css/*.less")
        .pipe(less())
        .pipe(concat("index.css"))
        .pipe(cleanCSS({ compatibility: 'ie8' }))
        .pipe(rename(path => {
            // 这里我们只需要修改basename属性即可
            // 若需要查看有哪些可修改属性请
            // console.log(path)

            path.basename += "-min";
        }))
        .pipe(gulp.dest("dist/css"))
})

// 默认任务
gulp.task("default", gulp.parallel(
    "minifyJS", "tfLess"
));

rename差不多到这就行了,我们重命名一般都是+个.min之类的,所以够用了

  • del

你会发现如果在你没有删文件的前提下,你的dist文件夹下的文件应该可以说是非常的多了吧,绝对不是一个文件夹对一个一个文件了吧,那么这是楼主的目录结构


目录结构

你就会发现每一次的构建都会生成一个新的文件,如果文件名以替换又会生成一个新的文件,这样的话我们dist目录下可能就会出现很多无用的文件了,这时候我们就需要使用这个插件了

npm install --save-dev del

然后我们可能需要稍微改动一下默认task,这里建议大家使用series函数包裹,因为这样可以指定最后一个函数为default的处理函数,用parallel就不行

const gulp = require("gulp")
const uglify = require("gulp-uglify")
const babel = require("gulp-babel")
const less = require("gulp-less")
const cleanCSS = require("gulp-clean-css")
const concat = require("gulp-concat")
const rename = require("gulp-rename")
const del = require("del")


// 任务名就是函数的名字
gulp.task(async function minifyJS() {
    // []表示匹配多个源,!就是正则表达式的非 的->意思
    gulp.src(["js/*.js", "!js/*.min.js"])
        .pipe(babel({
            presets: ["@babel/env"]
        }))
        // 在压缩之前合并js文件
        // 需要换入合并之后的文件名
        .pipe(concat("all.js"))
        .pipe(uglify())
        .pipe(rename(path => {
            // 这里我们只需要修改basename属性即可
            // 若需要查看有哪些可修改属性请
            // console.log(path)

            path.basename += "-min";
        }))
        .pipe(gulp.dest("dist/js"))
})

gulp.task(async function tfLess() {
    gulp.src("css/*.less")
        .pipe(less())
        .pipe(concat("index.css"))
        .pipe(cleanCSS({ compatibility: 'ie8' }))
        .pipe(rename(path => {
            // 这里我们只需要修改basename属性即可
            // 若需要查看有哪些可修改属性请
            // console.log(path)

            path.basename += "-min";
        }))
        .pipe(gulp.dest("dist/css"))
})

gulp.task(async function cleanDir(){
    // 删除dist目录下所有文件/目录
    // 也可以传入一个数组删除多个文件或者目录等等
   return del("dist/**/*")
})


// 默认任务
gulp.task("default", gulp.series(
    "cleanDir",
    gulp.parallel("minifyJS", "tfLess")
));

这样我们就实现了一个使用先删除输出文件夹下所有文件然后再输出的功能

  • gulp-markdown

这个插件怎么说呢?对于我们而言还是有点作用的,这个插件可以将md文件语法转换成html输出

npm install --save-dev gulp-markdown
const gulp = require("gulp")
const uglify = require("gulp-uglify")
const babel = require("gulp-babel")
const less = require("gulp-less")
const cleanCSS = require("gulp-clean-css")
const concat = require("gulp-concat")
const rename = require("gulp-rename")
const del = require("del")
const markdown = require("gulp-markdown")


// 任务名就是函数的名字
gulp.task(async function minifyJS() {
    // []表示匹配多个源,!就是正则表达式的非 的->意思
    gulp.src(["js/*.js", "!js/*.min.js"])
        .pipe(babel({
            presets: ["@babel/env"]
        }))
        // 在压缩之前合并js文件
        // 需要换入合并之后的文件名
        .pipe(concat("all.js"))
        .pipe(uglify())
        .pipe(rename(path => {
            // 这里我们只需要修改basename属性即可
            // 若需要查看有哪些可修改属性请
            // console.log(path)

            path.basename += "-min";
        }))
        .pipe(gulp.dest("dist/js"))
})

gulp.task(async function tfLess() {
    gulp.src("css/*.less")
        .pipe(less())
        .pipe(concat("index.css"))
        .pipe(cleanCSS({ compatibility: 'ie8' }))
        .pipe(rename(path => {
            // 这里我们只需要修改basename属性即可
            // 若需要查看有哪些可修改属性请
            // console.log(path)

            path.basename += "-min";
        }))
        .pipe(gulp.dest("dist/css"))
})

gulp.task(async function cleanDir(){
    // 删除dist目录下所有文件/目录
    // 也可以传入一个数组删除多个文件或者目录等等
   return del("dist/**/*")
})

gulp.task(async function tfMD(){
    gulp.src("md/01.md")
        .pipe(markdown())
        .pipe(gulp.dest("dist/md"))
})

// 默认任务
gulp.task("default", gulp.series(
    "cleanDir",
    gulp.parallel("minifyJS", "tfLess")
));
  • gulp-imagemin

压缩 PNG, JPEG, GIF 和 SVG 图片的一个插件

npm install --save-dev gulp-imagemin

(使用起来都是一样的)

  • gulp.spritesmith

这东西对于前端的性能优化来说还是挺有用的,可以将多张图片合并为一张精灵图,这样可以减少很多http请求,明白吧!

(这两个插件后续更新,因为目前没有合适的图片使用)

(其实gulp有许多的有意思的小插件,大家可以去gulp的插件市场浏览一下)

分享一些使用gulp中遇到的问题

  1. 最新的gulp4,在进行使用gulp.series进行顺序task或者异步taskgulp.parallel的时候会出现一些,就是你会发现使用了async函数,会出现顺序无法按照预期的顺序执行task,但是如果使用done回调函数的话,因为stream是异步的而且gulp.dest没有提供回调,io操作不知道什么时候完成也解决不了这个问题,这就陷入了一个死节了,不知道应该怎么办?后面我是怎么做的呢,好像gulp官方要求series或者parallel返回一个stream,所以说后面我按照这个要求去掉了async去掉了done回调,直接返回一个gulp.src解决问题了,可以给大家看一下最近我写的一个gulpfile.js
const gulp = require("gulp");
const cssClean = require('gulp-clean-css');
const rename = require("gulp-rename");
const uglify = require("gulp-uglify");
// 两个插件用于修改html文件中的引用资源路径
const rev = require('gulp-rev');
// 通过此插件改写html引用的路径
const revReplace = require('gulp-rev-replace');
const htmlmin = require('gulp-htmlmin');


const del = require("del");


gulp.task("cleanDir", () => del("qian/**"))

// minify css
gulp.task('cssMin', () => {
    return gulp.src("qian/css/*.css")
        .pipe(cssClean({ compatibility: 'ie9' }))
        .pipe(gulp.dest('qian/css'));
});


// uglify js --> 同时压缩了代码,混肴了代码
gulp.task(function jsMin() {
    return gulp.src("qian/js/*.js")
        .pipe(uglify())
        .pipe(gulp.dest("qian/js"));
})


// 首先生成对应的manife.json文件然后进行优化对应文件,最后替换路径
gulp.task(function genManifest() {
    return gulp.src(["dist/css/*.css", "dist/js/*.js"], { base: "dist" })
        // .pipe(gulp.dest('qian'))
        .pipe(rev())
        .pipe(rename(path => {
            // console.log(path);
            path.basename += ".min";
        }))
        .pipe(gulp.dest('qian'))
        .pipe(rev.manifest())
        .pipe(gulp.dest('qian/rev'))
})

gulp.task(function Done() {
    return gulp.src("dist/index.html")
        .pipe(revReplace({ manifest: gulp.src("qian/rev/*.json") }))
        .pipe(htmlmin({
            minifyJS: true,
            minifyCSS: true,
            removeComments: true, //清除HTML注释
            collapseWhitespace: true, //压缩HTML
        }))
        .pipe(gulp.dest("qian"))
})


gulp.task("default", gulp.series(
    "cleanDir",
    gulp.parallel("cssMin", "jsMin"),
    "genManifest",
    "Done",
    function myHook(){
        return gulp.src("dist/favicon.ico").pipe(gulp.dest("qian"));
    }
));
  1. 关于上面的写这个gulpfile.js的时候又遇到了新的问题,因为使用了webpack打包这些东西,使用gulp构建的时候出现了一些问题,就是比如说我们需要去压缩css或者混肴压缩js或者压缩html等等那么我们需要标准化文件的名称为+-min,因为是自动化的工具,所以我们需要自动化啊,但是如果我们更改了这些资源的名称,那么我们就需要手动的去修高html文件中的资源引用路径,这就不符合自动化的观念了,所以后面通过搜集资料开始了解到了两个插件
    gulp-rev
    gulp-rev-collector

那么根据一些资料,大概就是通过gulp-rev生成修改之前的文件资源的路径与生成之后的文件资源路径的对应关系为一个json文件,然后gulp-rev-collector插件通过解析这个json文件,进行正则匹配html文件中对应的资源进行替换资源

  1. 那么这是我html文件中的引用关系


    image.png
  2. 通过gulp生成的对应关系


    image.png

那么这里主要是想跟大家分享一些解决这些问题的经验,避免少走弯路,那么之后出现了一个什么问题了,发现生成之后的html文件根本就没有替换静态引用资源路径,真的,为了解决这个问题花了3个小时的时间,当时解决的差点怀疑人生了,最后我抛开了自己的问题,觉得肯定是这个插件的问题!

所以我又遇见了另一个插件
gulp-rev-replace
真的,解决这个问题差点搞得我崩溃,那么替换为上面这个插件之后,问题基本上就已经完美解决了,白花花花了3个小时的时间,希望大家千万不要踩坑用哪个坑爹的gulp-rev-collector,当然也有可能是因为楼主用的姿势不对,但是不管怎么说如果你用这个插件如果不行,千万不要考虑解决,直接换上面这个replace插件吧
还有就是如果需要动态的替换这些引用资源的路径,必须要保证在rev生成的manife.json文件之后不要修改 文件名切记

问题分享就到这了

教程远没有结束,如果还有可以分享的插件,我也会一直更新下去,记得查看最后时间哦

有没有啥相对我说的或者交流的或者你对学习前端有困惑什么的,可以联系我哈群78484-->5854,偷偷告诉你楼主是自学的,并且不会英语哦

last update: 2019年8月22日 22点12

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

推荐阅读更多精彩内容