前端工程自動化工具gulp配置使用心得

???? gulp是一款非吃舻耍火熱的前端工程自動化工具,可以實現(xiàn)諸多任務(wù)的自動執(zhí)行來提升開發(fā)效率匆骗。有了gulp可以幫助我們實現(xiàn)es2015+向es5、es3的轉(zhuǎn)化,對sass、less的轉(zhuǎn)化,頁面熱更新等只损,大大解放了我們的雙手,帶來了一種全新的開發(fā)體驗。

???? 今天花了大半天的時間,跟著老師的視頻一步一的搭建gulp前端工程自動化環(huán)境闲勺,總的來說申尤,還是挺流暢的橙喘,但是也踩了不少的坑磁奖。比如身诺,gulp和webpack等工具版本的更新幔托,在使用方式上有一些不一樣的地方谬哀。下面我就將我的配置配置過程分享出來谦屑,如果你能刷到這篇帖子充蓝,并且能對您有多幫助卑笨,那么我將會無比的開心桶良。
???? 首先疲牵,要說明的是,我這里打算使用gulp4.x责静,雖然講課的老師用的是gulp3.x,反正要學就學最新的熄赡,沒錯的。

一、需求分析

???? 我們的目的就是礁凡,放心地寫代碼紊浩,使用最新的ecmascript語法,能夠自動地監(jiān)聽文件的變化,頁面能夠熱重載,我們就是想讓gulp幫我們完成這些繁瑣的工作调榄。

二伦籍、項目目錄介紹

image.png

從圖中可以看出剩燥,我們的目錄只主要有三個大的分類,分別是/app, /server, /tasks,至于其功能,我已經(jīng)在圖上做了標注苦丁。

三棵磷、通過express框架生成服務(wù)端代碼

express -e .
npm install

???? 通過上面的兩行命令赌莺,服務(wù)端的環(huán)境就查創(chuàng)建好了,express框架不在過多介紹傲绣。

四禁舷、構(gòu)建gulp任務(wù)

1、編寫gulpfile.babel.js文件

???? 因為我們要使用babel途茫,所以這里建立的文件名為gulpfile.babel.js,具體地可以這個https://www.gulpjs.com.cn/docs/getting-started/javascript-and-gulpfiles/鏈接。

import requireDir from "require-dir";
requireDir("./tasks");

???? gulpfile.babel.js中的內(nèi)容很簡單,因為我們所有的gulp任務(wù)都是放在/tasks目錄下的租谈,所以我們需要在gulpfile.babel.js中引入整個/tasks目錄憔足,當然你需要安裝“require-dir”,由于本項目中需要安裝的第三方包比較多州袒,所以我們會在最后統(tǒng)一給出要安裝的包的列表。

2姐扮、創(chuàng)建命令行輸入工具集

???? 在進行下面所有的操作時杯缺,我們可以先創(chuàng)建一個可以在命令行進行交互的工具亲铡,這個工具我們使用第三方包來進行構(gòu)建疑务。
新建文件/tasks/util/args.js

import yargs from "yargs";

const args = yargs
  .option("production", {
    boolean: true,
    default: false,
    describe: "min all scripts",
  })
  .option("watch", {
    boolean: true,
    default: false,
    describe: "watch all files",
  })
  .option("verbose", {
    boolean: true,
    default: false,
    describe: "log",
  })
  .option("sourcemaps", {
    describe: "force the creation of soucemaps",
  })
  .option("port", {
    string: true,
    default: 8080,
    describe: "server port",
  });

???? 這個文件的具體內(nèi)容就不做過多的解釋了,其目的只要是可以接受到命令輸入的一些參數(shù)纺阔。比如在命令行輸入

gulp --watch

???? 那么批什,我們就可以用args.watch來獲取到這個數(shù)據(jù),用來判斷在后續(xù)的任務(wù)是否中監(jiān)聽文件變化的操作碧信。

3、創(chuàng)建轉(zhuǎn)化js的任務(wù)

???? 在這個構(gòu)建任務(wù)中,最重要也最繁瑣的就算是對js的處理了歧杏,因為要涉及到對es2015+代碼的處理,所以搞懂了對js任務(wù)的處理迷守,就能搞懂對其他任務(wù)的處理犬绒,如css,ejs模版引擎等兑凿。
新建/tasks/scripts.js

import gulp from "gulp";
import gulpif from "gulp-if";
import concat from "gulp-concat";
import webpack from "webpack";
import gulpWebpack from "webpack-stream";
import named from "vinyl-named";
import livereload from "gulp-livereload";
import plumber from "gulp-plumber";
import rename from "gulp-rename";
import uglify from "gulp-uglify";
import { log, colors } from "gulp-util";
import args from "./util/args";

gulp.task("default", () => {
  return gulp
    .src(["app/js/index.js"])
    .pipe(
      plumber({
        errorHandle: function () {},
      })
    )
    .pipe(named())
    .pipe(
      gulpWebpack({
        module: {
          rules: [{ test: /\.js$/, loader: "babel-loader" }],
        },
      })
    )
    .pipe(gulp.dest("server/public/js"))
    .pipe(
      rename({
        basename: "cp",
        extname: ".min.js",
      })
    )
    .pipe(
      uglify({ compress: { properties: false }, output: { quote_keys: true } })
    )
    .pipe(gulp.dest("server/public/js"))
    .pipe(gulpif(args.watch, livereload()));
});

???? 這段代碼中引入的第三方模塊比較多凯力,下面先來看一下他們各自的功能茵瘾,至于具體的使用,我們可以在npm官網(wǎng)上自行查看(英文好針真的很重要)咐鹤。

名稱 功能
gulp -
gulp-if gulp中做if循環(huán)判斷用
gulp-concat 合并文件拗秘,減少功能請求
webpack -
webpack-stream 以流的形式運行webpack,方便地與gulp集成
vinyl-named 給文件起名字
gulp-livereload 實現(xiàn)頁面地熱更新
gulp-plumber 防止由gulp插件錯誤引起的管道破裂
gulp-rename 對文件重命名
gulp-uglify 壓縮js文件
gulp-util gulp提供地工具函數(shù)(已經(jīng)被棄用了)

???? 另外一個我們應(yīng)該注意地是祈惶,這個任務(wù)我們起名字叫default雕旨,因為gulp會首先區(qū)尋找gulp任務(wù)中地default任務(wù)去執(zhí)行,為了測試地方便我們把它設(shè)置了default捧请,等所有地開發(fā)完畢之后凡涩,我們會將其重新命名為scripts
???? 首先疹蛉,我們先看一下gulp常用的api方法及其功能如下圖所示:

api 用途
src() 接受 glob 參數(shù)活箕,并從文件系統(tǒng)中讀取文件然后生成一個 Node 流(stream)。它將所有匹配的文件讀取到內(nèi)存中并通過流(stream)進行處理氧吐。
dest() dest() 接受一個輸出目錄作為參數(shù)讹蘑,并且它還會產(chǎn)生一個 Node 流(stream),通常作為終止流(terminator stream)筑舅。當它接收到通過管道(pipeline)傳輸?shù)奈募r座慰,它會將文件內(nèi)容及文件屬性寫入到指定的目錄中
pipe() 用于連接轉(zhuǎn)換流(Transform streams)或可寫流(Writable streams)
- src() 也可以放在管道(pipeline)的中間,以根據(jù)給定的 glob 向流(stream)中添加文件翠拣。新加入的文件只對后續(xù)的轉(zhuǎn)換可用版仔。如果 glob 匹配的文件與之前的有重復(fù),仍然會再次添加文件误墓。
- dest() 可以用在管道(pipeline)中間用于將文件的中間狀態(tài)寫入文件系統(tǒng)蛮粮。當接收到一個文件時,當前狀態(tài)的文件將被寫入文件系統(tǒng)谜慌,文件路徑也將被修改以反映輸出文件的新位置然想,然后該文件繼續(xù)沿著管道(pipeline)傳輸。
watch() watch() 方法利用文件系統(tǒng)的監(jiān)控程序(file system watcher)將 globs任務(wù)(task) 進行關(guān)聯(lián)欣范。它對匹配 glob 的文件進行監(jiān)控变泄,如果有文件被修改了就執(zhí)行關(guān)聯(lián)的任務(wù)(task)

???? 當然,gulp還有很多一些api和比較難的東西恼琼,本人也沒有太深入的理解妨蛹,可以到gulp的官方文檔上面進行查閱。
???? 了解了常用的方法api后晴竞,我們可以對上面的任務(wù)流程進行逐步分解了蛙卤,具體地請看下表:

流程
1.src()讀取文件,產(chǎn)生文件元數(shù)據(jù)對象
2. plumber()對讀取過程中的錯誤進行處理,防止碎裂管道
3. named ()對文件進行任意命名
4. gulpWebpack ()使用webpack對模塊進行處理颤难,包括babel轉(zhuǎn)換等
5. dest ()保存階段性中間文件
6.rename()對文件進行重命名操作
7. uglify ()壓縮代碼
8.dest()保存處理后的文件
9.watch()監(jiān)聽文件的變化神年,對資源進行熱更新操作

4、對模版的處理

新建/tasks/pages.js

import gulp from "gulp";
import gulpif from "gulp-if";
import livereload from "gulp-livereload";
import args from "./util/args";

gulp.task("default", () => {
  return gulp
    .src("app/**/*.ejs")
    .pipe(gulp.dest("server"))
    .pipe(gulpif(args.watch, livereload()));
});

???? 相對于對js的處理行嗤,對模版的處理就顯得比較簡單了瘤袖,有一點需要注意,

.pipe(gulp.dest("server"))

???? 這個地方昂验,我們把文件最終輸入地址定為“server”,但是我們的目標地址是“server/views”呀艾扮,這是怎么回事呀既琴。根據(jù)官網(wǎng)文檔的解釋,在src方法中/.ejs之前叫在使用dest()方法的時候會被省去泡嘴,也就是會把/.ejs保留下來甫恩,也就是會把views/index.ejs保留下來。所以上面的操作就是OK的酌予。

5磺箕、對css的處理

新建/tasks/css.js

import gulp from "gulp";
import gulpif from "gulp-if";
import livereload from "gulp-livereload";
import args from "./util/args";

gulp.task("css", () => {
  return gulp
    .src("app/**/*.css")
    .pipe(gulp.dest("server/public"))
    .pipe(gulpif(args.watch, livereload()));
});

5、監(jiān)聽服務(wù)端代碼的變化

新建/tasks/server.js

import gulp from "gulp";
import gulpif from "gulp-if";
import liveserver from "gulp-live-server";
import args from "./util/args";

gulp.task("server", (cb) => {
  if (!args.watch) return cb();

  var server = liveserver.new(["--harmony", "server/bin/www"]);
  server.start();

  gulp.watch(["server/public/**/*.js", "server/public/**/*.ejs"], function (
    file
  ) {
    server.notify.apply(server, [file]);
  });

  gulp.watch(["server/routes/**/*.js", "server/app.js"], function () {
    server.start.bind(server)();
  });
});

???? 這個任務(wù)自然是監(jiān)聽服務(wù)端代碼的更改的抛虫,當然我們需要安裝第三方包gulp-live-server來幫助我們實現(xiàn)這個功能松靡,至于這個包的具體用法,可以自行查看npm包建椰。

6雕欺、創(chuàng)建瀏覽器監(jiān)聽任務(wù)

新建/tasks/brower.js
???? 上面我們完成的任務(wù)中,server是對/server目錄下的文件變化進行監(jiān)聽棉姐,scripts是將/app/js目錄下的js文件打包進/server/js目錄下屠列,css和pages任務(wù)也都是實現(xiàn)了類似的功能。現(xiàn)在的問題是伞矩, 一旦/app目錄中的文件發(fā)生了變化笛洛,怎么樣通過pages、css乃坤、scripts等任務(wù)苛让,將變化后的文件更新到/server目錄下。這里我們就需要創(chuàng)建brower這個任務(wù)了侥袜,通過這個任務(wù)蝌诡,我們可以實時監(jiān)聽文件的變化,最后將變化后的文件存放到/server目錄下枫吧。

import gulp from "gulp";
import gulpif from "gulp-if";
import gutil from "gulp-util";
import args from "./util/args";

gulp.task("brower", (cb) => {
  if (!args.watch) return cb();
  gulp.watch("app/**/*.js", ["scripts"]);
  gulp.watch("app/**/*.ejs", ["pages"]);
  gulp.watch("app/**/*.css", ["css"]);
});

7浦旱、清除之前打包文件的任務(wù)(clean)

新建/tasks/clean.js
???? 在前端代碼(/app目錄下)發(fā)生改變后,改變后的文件就會被保存在/server目錄下九杂,為了使打包后的代碼保持干凈颁湖,我們希望在每次打包之前都能清除掉/server/public 目錄下的內(nèi)容宣蠕,那么我們就新建了一個clean任務(wù)。

import gulp from "gulp";
import del from "del";
import args from "./util/args";

gulp.task("clean", () => {
  return del(["server/public", "server/views"]);
});

8甥捺、構(gòu)建打包(整個流程結(jié)構(gòu))任務(wù)(build)

???? 通過上面所有的任務(wù)抢蚀,我們可以實現(xiàn)我們所有的需求了,現(xiàn)在是時候來把這個流程梳理一下了镰禾,把他們存進一個隊列中皿曲,讓他們按照指定順序進行。
新建/tasks/build

import gulp from "gulp";
import gulpSequence from "gulp-sequence";

gulp.task(
  "build",
  gulpSequence("clean", "css", "pages", "scripts", ["browser", "server"])
);

從build任務(wù)中吴侦,我們可以看出屋休,我們將要依次進行cleancss备韧、pages劫樟、scripts、["brower","server"]任務(wù)织堂。

9.設(shè)置任務(wù)入口

???? 因為gulp默認會尋找default任務(wù)叠艳,也就是說default任務(wù)是我們?nèi)蝿?wù)的主入口。
新建/tasks/default.js

import gulp from "gulp";
gulp.task("default", ["build"]);

四易阳、運行附较、調(diào)試、優(yōu)化

???? 終于把環(huán)境配置好了闽烙,是不是我們就可以愉快的使用我們的環(huán)境來做一些非常有趣的事情呢翅睛,但是當在命令行運行 gulp 命令時,會先后報兩個錯誤黑竞。
錯誤一:忘記了
位置:/tasks/default.js

// 不能使用這種方式
gulp.task("default", ["build"]);
// 要使用下面的這種方式
gulp.task("default", gulp.series("build"));

錯誤二:TypeError: gulp.on(...).on(...).on(...).on(...).start is not a function
位置:/tasks/build.js
原因:gulp4 不再支持下面的調(diào)用捕发,要使用gulp.series()的這種方式

gulp.task(
  "build",
  gulpSequence("clean", "css", "pages", "scripts", ["browser", "server"])
);

經(jīng)過查找資料得知,這都是gulp升級到4.x帶來的后果很魂,沒辦法扎酷,只能將版本后降到3.x。

npm install --save-dev gulp@3.9.1

???? 再次用gulp 遏匆,我們的任務(wù)都跑完了法挨,沒毛病,但是幅聘,怎么服務(wù)器沒有啟動呀凡纳,瀏覽器輸入了http://localhost:3000x顯示服務(wù)器沒有啟動,怎么辦帝蒿,找了一圈荐糜,發(fā)現(xiàn)/tasks/util/args.js 沒有導(dǎo)出模塊,乖乖加上吧。

export default args;

???? 這次確實可以了暴氏,服務(wù)器也起來了延塑,但是頁面顯示為白板,這是因為我們的/app/views/index.ejs中沒有任何內(nèi)容呀答渔,添加內(nèi)容后关带,刷新頁面,內(nèi)容也出來了沼撕。

???? 美中不足的是宋雏,這個刷新得讓我們手動實現(xiàn),有沒有辦法修改文件保存后自動刷新了务豺,答案肯是有的好芭。不過我們又得借助第三方的模塊connect-livereload。
在/server/app.js中添加代碼

app.use(express.static(path.join(__dirname, "public")));
app.use(require("connect-livereload")());
app.use("/", indexRouter);

???? 注意冲呢,前兩行代碼一種不能呼喚位置,也就是說第二行的代碼一直要在第一行代碼執(zhí)行之后執(zhí)行招狸,這樣會保證資源加載完全敬拓。
???? 好了,已經(jīng)是凌晨1點了裙戏,就這樣吧乘凸。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市累榜,隨后出現(xiàn)的幾起案子营勤,更是在濱河造成了極大的恐慌,老刑警劉巖壹罚,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件葛作,死亡現(xiàn)場離奇詭異,居然都是意外死亡猖凛,警方通過查閱死者的電腦和手機赂蠢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辨泳,“玉大人虱岂,你說我怎么就攤上這事〔ず欤” “怎么了第岖?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長试溯。 經(jīng)常有香客問我蔑滓,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任烫饼,我火速辦了婚禮猎塞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘杠纵。我一直安慰自己荠耽,他們只是感情好,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布比藻。 她就那樣靜靜地躺著铝量,像睡著了一般。 火紅的嫁衣襯著肌膚如雪银亲。 梳的紋絲不亂的頭發(fā)上慢叨,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機與錄音务蝠,去河邊找鬼拍谐。 笑死,一個胖子當著我的面吹牛馏段,可吹牛的內(nèi)容都是我干的轩拨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼院喜,長吁一口氣:“原來是場噩夢啊……” “哼亡蓉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起喷舀,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤砍濒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后硫麻,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體爸邢,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年拿愧,在試婚紗的時候發(fā)現(xiàn)自己被綠了甲棍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡赶掖,死狀恐怖感猛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情奢赂,我是刑警寧澤陪白,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站膳灶,受9級特大地震影響咱士,放射性物質(zhì)發(fā)生泄漏立由。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一序厉、第九天 我趴在偏房一處隱蔽的房頂上張望锐膜。 院中可真熱鬧,春花似錦弛房、人聲如沸道盏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荷逞。三九已至,卻和暖如春粹排,著一層夾襖步出監(jiān)牢的瞬間种远,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工顽耳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坠敷,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓射富,卻偏偏與公主長得像常拓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子辉浦,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容