一文學會gulp

說一下前端的自動化構建工具gulp吧,其實國內的前端自動化工具比較流行的還有就是fisgrunt了咐刨,但是我覺得目前gulp的社區(qū)相對友好,而且關于gulp也是特別容易快速上手的

請一定要看我貼的代碼扬霜,因為許多的gulp知識我都是通過粘貼代碼附帶對應的注釋的方式講解的定鸟,這樣的話你不懂代碼就在下邊可以結合注釋講解快速入門gulp的

那么首先我們先進行全局安裝gulp

npm i -g gulp

然后我們需要在我們需要構建的項目中局部安裝一個本地開發(fā)依賴gulp

npm i -D gulp

然后我們需要新建一個用于執(zhí)行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函數(shù)华糖,而不是箭頭函數(shù)
// task函數(shù)可以聲明一個gulp的task,那么默認gulp是以task進行工作的
// 每一部分的構建都可以細分不同的task
gulp.task("minify",function(){
    // 第一個參數(shù)為task的名字瘟裸,盡量是一看名字就知道是干啥的那種
    // 這里是運行這個任務的邏輯
    
    

    // src函數(shù)客叉,gulp是以數(shù)據(jù)流的方式進行構建我們的代碼的
    // 所以我們需要使用src函數(shù)為gulp提供一個需要待處理的輸入流數(shù)據(jù)
    gulp.src("./js/01.js")
    // 然后我們可以通過管道的方式讓不同的插件處理這些數(shù)據(jù)
    .pipe(uglify())
    // 同樣的我們需要通過管道將這些數(shù)據(jù)輸出出去
    // 這里我們使用dest函數(shù)代表輸出經(jīng)過處理的src函數(shù)提供的數(shù)據(jù)流
    .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();

然后現(xiàn)在是不是特別的激動呢话告?我們現(xiàn)在是萬事俱備兼搏,只欠東風了,那么我們快速打開我們的cmd工具定位到當前目錄下吧沙郭,然后我們運行

gulp taskname
// 這里我們
gulp minify

執(zhí)行這個task吧佛呻,我們看看效果吧


效果

大家一定要注意啊,這個坑爹的uglify是不能夠壓縮es6js語法的病线,直接報錯明白吧吓著,剛開始寫的是classclass`后面幾次報錯就改成原始寫法了,賊坑送挑,注意

然后我們就會發(fā)現(xiàn)我們的代碼已經(jīng)打包好了

打包好了

那么大家還會發(fā)現(xiàn)控制臺報了一個錯誤绑莺,大致意思好像是說這個task沒有完成,需要異步執(zhí)行惕耕,這里就有兩種解決辦法了纺裁,我們可以直接給task后面的函數(shù)加上async關鍵字

image.png

完美解決,第二種就是可以給task后面的邏輯處理函數(shù)接受一個可選的done回調主動告訴gulp任務完成

image.png

同樣的可以完美解決司澎,但是還是建議大家使用async關鍵字对扶,使用異步函數(shù)解決此問題区赵,異步就是不可控性,其實你并不知道他什么時候就能夠執(zhí)行完成浪南,所以有些時候根本不知道什么時候回調done函數(shù)笼才,請大家選擇第一種方式

關于第一個插件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的默認任務助析,我們現(xiàn)在是個什么情況犀被,我們現(xiàn)在就是每一次聲明一個任務然后就必須在控制臺中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啊,到這時候我們還是沒有發(fā)現(xiàn)gulp哪里自動化了,繼續(xù)繼續(xù)繼續(xù)

  • 任務的依賴

順序執(zhí)行

關于gulp任務的依賴祠汇,就是實現(xiàn)自動化的最大一特性仍秤,配合gulp的默認task可以迅速實現(xiàn)gulp的自動化

這里主要說說gulp最新版本gulp4的任務依賴,gulp3跟gulp改動還是稍微有點大的可很,還有就是目前(2019年7月13日-11點16分)gulp中文網(wǎng)的文檔還是gulp3的但是我們現(xiàn)在安裝的gulp已經(jīng)默認為gulp4了诗力,同時也推薦大家使用gulp4,因為gulp4對比gulp3優(yōu)化了很多東西

然后這里我從頭開始寫一個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函數(shù)可以傳遞一系列的任務進去被順序執(zhí)行(順序苇本,不是并行的)
    // 所以會出現(xiàn)先執(zhí)行前面一個再執(zhí)行后面一個,然后因為這是順序執(zhí)行的所以我們可以將default任務的處理函數(shù)放在最后
    // 但是大家要明白series函數(shù)接收的是一個個任務菜拓,這就意味著一個函數(shù)也可以成為一個任務瓣窄,我們后面添加一個three試試
    console.log("done")
}))
done

這里的報錯因為沒有調用done并且還不是異步函數(shù),所以出錯了

const gulp = require("gulp")

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


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

// 這里可以直接通過task方法將這個函數(shù)轉換為對應的任務
async function three(done){
    console.log(three);
}
gulp.task(three);


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

并行執(zhí)行

然后我這里寫了這些代碼

const gulp = require("gulp")

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


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

// 這里可以直接通過task方法將這個函數(shù)轉換為對應的任務
async function three(done){
    let i = 0;
    while(i<10000){
        i++;
    }
    console.log("three執(zhí)行完成");
}
gulp.task(three);


// parallel函數(shù)跟series函數(shù)差不多纳鼎,只不過里面的任務會并行執(zhí)行
gulp.task("default",gulp.parallel("one","two","three",async function(){
    let i = 0;
    while(i<10000){
        i++;
    }
    console.log("這是并行執(zhí)行的俺夕,我不一定是最后一個輸出了");
}))

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


并行

這真的是并行執(zhí)行的贱鄙,你沒發(fā)現(xiàn)一次性開始了所有的任務又然后中間輸出又完成所有的任務了嗎劝贸?看看series的控制臺情況吧


對比

對比一下就知道這是并行執(zhí)行的了

嵌套

這是gulp的一個超級大亮點,就是并行和順序任務可進行過互相嵌套贰逾,并行可以嵌套在順序中悬荣,順序可以嵌套在并行中

const gulp = require("gulp")

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


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

// 這里可以直接通過task方法將這個函數(shù)轉換為對應的任務
async function three(done){
    console.log("我第三");
}
gulp.task(three);


// 這就代表著會優(yōu)先并行執(zhí)行one菠秒,two等待這兩個task結束后疙剑,在順序執(zhí)行three和最后的回調函數(shù)
gulp.task("default",gulp.series(gulp.parallel("one","two"),"three",async function(){
    console.log("我最后");
}))

可以互相嵌套,靈活運用哦


image.png
  • watch

自動化怎么可能少得了監(jiān)聽呢践叠?一個監(jiān)聽使用的小小例子

const gulp = require("gulp")

gulp.task("watch",async function(){
    // 指定監(jiān)聽的文件
    gulp.watch("js/*.js",done=>{
        // 可以指定一個具體的回調函數(shù)言缤,或者指定一個或多個任務進行處理
        console.log("修改了js文件");
        done();
    })
})

也可以使用綁定事件監(jiān)聽的方式完成文件的監(jiān)聽

const gulp = require("gulp")

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

gulp.task("watch",async function(){
//每一個監(jiān)聽具體什么作用大家自己可以測試一下
    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文件夾在下邊創(chuàng)建一個less文件,其實gulp跟webpack還是有所不同的斋荞,因為gulp不像webpack那樣通過一個入口文件開始整合資源代碼那樣荞雏,gulp直接可以定義任務然后自動執(zhí)行就行了

@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")

// 任務名就是函數(shù)的名字
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并發(fā)執(zhí)行兩個task悦陋,因為這兩個task的執(zhí)行并不會互相沖突,然后我們就可以在命令行運行gulp看看了

body {
  color: red;
}

那么這就是我轉換之后的css文件了筑辨,你會發(fā)現(xiàn)為什么這個css文件有點不大對勁譬重,對!其實就是沒有進行壓縮啊

  • gulp-clean-css

壓縮css代碼在gulp中我們可以使用這個插件完成祷蝌,那么我看了一下這個插件的下載量還是有點客觀的婉支,就沒有使用另一款插件了(gulp-csso)

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

那么我們安裝完成這個插件之后怎么用呢,其實就是繼續(xù)在剛剛那個處理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")


// 任務名就是函數(shù)的名字
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文件就發(fā)現(xiàn)已經(jīng)完全的minify了送矩,那么關于這個插件,介紹是說這個插件是clean-css在gulp上的實現(xiàn)哪替,其實就是包裝了一下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");

為了節(jié)省時間就隨便寫了幾行代碼,然后我們快速安裝使用下吧

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")


// 任務名就是函數(shù)的名字
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"
));

你就會發(fā)現(xiàn)合并竟然是如此的簡單匆背,你以為這樣就結束了,不你錯了身冀,它不僅可以合并js文件同樣也可以合并css文件钝尸,你明白吧,只需要修改對應的css文件處理任務函數(shù)

    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")


// 任務名就是函數(shù)的名字
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

你會發(fā)現(xiàn)如果在你沒有刪文件的前提下,你的dist文件夾下的文件應該可以說是非常的多了吧仁卷,絕對不是一個文件夾對一個一個文件了吧穴翩,那么這是樓主的目錄結構


目錄結構

你就會發(fā)現(xiàn)每一次的構建都會生成一個新的文件,如果文件名以替換又會生成一個新的文件锦积,這樣的話我們dist目錄下可能就會出現(xiàn)很多無用的文件了芒帕,這時候我們就需要使用這個插件了

npm install --save-dev del

然后我們可能需要稍微改動一下默認task,這里建議大家使用series函數(shù)包裹,因為這樣可以指定最后一個函數(shù)為default的處理函數(shù)充包,用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")


// 任務名就是函數(shù)的名字
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目錄下所有文件/目錄
    // 也可以傳入一個數(shù)組刪除多個文件或者目錄等等
   return del("dist/**/*")
})


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

這樣我們就實現(xiàn)了一個使用先刪除輸出文件夾下所有文件然后再輸出的功能

  • 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")


// 任務名就是函數(shù)的名字
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目錄下所有文件/目錄
    // 也可以傳入一個數(shù)組刪除多個文件或者目錄等等
   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

這東西對于前端的性能優(yōu)化來說還是挺有用的冠场,可以將多張圖片合并為一張精靈圖,這樣可以減少很多http請求本砰,明白吧碴裙!

(這兩個插件后續(xù)更新,因為目前沒有合適的圖片使用)

(其實gulp有許多的有意思的小插件点额,大家可以去gulp的插件市場瀏覽一下)

分享一些使用gulp中遇到的問題

  1. 最新的gulp4,在進行使用gulp.series進行順序task或者異步taskgulp.parallel的時候會出現(xiàn)一些,就是你會發(fā)現(xiàn)使用了async函數(shù),會出現(xiàn)順序無法按照預期的順序執(zhí)行task,但是如果使用done回調函數(shù)的話,因為stream是異步的而且gulp.dest沒有提供回調,io操作不知道什么時候完成也解決不了這個問題,這就陷入了一個死節(jié)了,不知道應該怎么辦?后面我是怎么做的呢,好像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文件然后進行優(yōu)化對應文件,最后替換路徑
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構建的時候出現(xiàn)了一些問題,就是比如說我們需要去壓縮css或者混肴壓縮js或者壓縮html等等那么我們需要標準化文件的名稱為+-min,因為是自動化的工具,所以我們需要自動化啊,但是如果我們更改了這些資源的名稱,那么我們就需要手動的去修高html文件中的資源引用路徑,這就不符合自動化的觀念了,所以后面通過搜集資料開始了解到了兩個插件
    gulp-rev
    gulp-rev-collector

那么根據(jù)一些資料,大概就是通過gulp-rev生成修改之前的文件資源的路徑與生成之后的文件資源路徑的對應關系為一個json文件,然后gulp-rev-collector插件通過解析這個json文件,進行正則匹配html文件中對應的資源進行替換資源

  1. 那么這是我html文件中的引用關系


    image.png
  2. 通過gulp生成的對應關系


    image.png

那么這里主要是想跟大家分享一些解決這些問題的經(jīng)驗,避免少走彎路,那么之后出現(xiàn)了一個什么問題了,發(fā)現(xiàn)生成之后的html文件根本就沒有替換靜態(tài)引用資源路徑,真的,為了解決這個問題花了3個小時的時間,當時解決的差點懷疑人生了,最后我拋開了自己的問題,覺得肯定是這個插件的問題!

所以我又遇見了另一個插件
gulp-rev-replace
真的,解決這個問題差點搞得我崩潰,那么替換為上面這個插件之后,問題基本上就已經(jīng)完美解決了,白花花花了3個小時的時間,希望大家千萬不要踩坑用哪個坑爹的gulp-rev-collector,當然也有可能是因為樓主用的姿勢不對,但是不管怎么說如果你用這個插件如果不行,千萬不要考慮解決,直接換上面這個replace插件吧
還有就是如果需要動態(tài)的替換這些引用資源的路徑,必須要保證在rev生成的manife.json文件之后不要修改 文件名切記

問題分享就到這了

教程遠沒有結束舔株,如果還有可以分享的插件,我也會一直更新下去还棱,記得查看最后時間哦

有沒有啥相對我說的或者交流的或者你對學習前端有困惑什么的载慈,可以聯(lián)系我哈群78484-->5854,偷偷告訴你樓主是自學的珍手,并且不會英語哦

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末办铡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子琳要,更是在濱河造成了極大的恐慌寡具,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稚补,死亡現(xiàn)場離奇詭異童叠,居然都是意外死亡,警方通過查閱死者的電腦和手機课幕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門厦坛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人撰豺,你說我怎么就攤上這事粪般∑从啵” “怎么了污桦?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匙监。 經(jīng)常有香客問我凡橱,道長,這世上最難降的妖魔是什么亭姥? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任稼钩,我火速辦了婚禮,結果婚禮上达罗,老公的妹妹穿的比我還像新娘坝撑。我一直安慰自己静秆,他們只是感情好,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布巡李。 她就那樣靜靜地躺著抚笔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪侨拦。 梳的紋絲不亂的頭發(fā)上殊橙,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音狱从,去河邊找鬼膨蛮。 笑死,一個胖子當著我的面吹牛季研,可吹牛的內容都是我干的敞葛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼与涡,長吁一口氣:“原來是場噩夢啊……” “哼制肮!你這毒婦竟也來了?” 一聲冷哼從身側響起递沪,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤豺鼻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后款慨,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體儒飒,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年檩奠,在試婚紗的時候發(fā)現(xiàn)自己被綠了桩了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡埠戳,死狀恐怖井誉,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情整胃,我是刑警寧澤颗圣,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站屁使,受9級特大地震影響在岂,放射性物質發(fā)生泄漏。R本人自食惡果不足惜蛮寂,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一蔽午、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酬蹋,春花似錦及老、人聲如沸抽莱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽岸蜗。三九已至,卻和暖如春叠蝇,著一層夾襖步出監(jiān)牢的瞬間璃岳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工悔捶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留铃慷,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓蜕该,卻偏偏與公主長得像犁柜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子堂淡,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內容