一文學會gulp

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

請一定要看我貼的代碼,因為許多的gulp知識我都是通過粘貼代碼附帶對應的注釋的方式講解的,這樣的話你不懂代碼就在下邊可以結(jié)合注釋講解快速入門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文件的內(nèi)容是

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回調(diào)主動告訴gulp任務完成

image.png

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

關于第一個插件gulp-uglify就說到此,接下來說一說gulp上面的babel插件,不然的話高階語法根本無法丑陋化,你懂我的意思吧

  • gulp-babel

關于gulp-babel就是gulp調(diào)用babel模塊轉(zhuǎn)換js語法而已,其實本質(zhì)上是一樣的,那么我們首先安裝項目依賴,這里推薦大家使用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目錄下看到被轉(zhuǎn)換后的代碼,就像這樣

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

這時候相信學到這里你就有點懵圈了,不是說好的自動化工具嗎?我怎么感覺我轉(zhuǎn)換了高階語法還要在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"));
})

// 轉(zhuǎn)換高階語法任務
gulp.task("tfSyntax",async function(){
    gulp.src("js/*.js")
        .pipe(babel({
            // 相當于babel配置文件
            presets:["@babel/env"]
        }))
        .pipe(gulp.dest("dist"))
})

那么我們這里在default任務中輸出123,那么我們直接在命令行中

gulp

直接gulp就行了,這樣就輸出了123,大家應該懂了什么叫做默認任務了吧!

然后我們就可以進行先轉(zhuǎn)換代碼再壓縮代碼的功能了

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文件夾下看到我們轉(zhuǎn)換壓縮之后的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

這里的報錯因為沒有調(diào)用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ù)轉(zhuǎn)換為對應的任務
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ù)轉(zhuǎn)換為對應的任務
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ù)轉(zhuǎn)換為對應的任務
async function three(done){
    console.log("我第三");
}
gulp.task(three);


// 這就代表著會優(yōu)先并行執(zhí)行one,two等待這兩個task結(jié)束后,在順序執(zhí)行three和最后的回調(diào)函數(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=>{
        // 可以指定一個具體的回調(diào)函數(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;
}

那么這就是我轉(zhuǎn)換之后的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)合并竟然是如此的簡單,你以為這樣就結(jié)束了,不你錯了,它不僅可以合并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文件夾下的文件應該可以說是非常的多了吧,絕對不是一個文件夾對一個一個文件了吧,那么這是樓主的目錄結(jié)構


目錄結(jié)構

你就會發(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文件語法轉(zhuǎn)換成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回調(diào)函數(shù)的話,因為stream是異步的而且gulp.dest沒有提供回調(diào),io操作不知道什么時候完成也解決不了這個問題,這就陷入了一個死節(jié)了,不知道應該怎么辦?后面我是怎么做的呢,好像gulp官方要求series或者parallel返回一個stream,所以說后面我按照這個要求去掉了async去掉了done回調(diào),直接返回一個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文件之后不要修改 文件名切記

問題分享就到這了

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

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

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

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容