前端的構(gòu)建工具常見(jiàn)的有Grunt、Gulp护戳、Webpack三種翎冲,Grunt比較老舊,功能少媳荒,更新少抗悍,插件少。
概念:
gulp是一個(gè)自動(dòng)化構(gòu)建工具钳枕,主要用來(lái)設(shè)定程序自動(dòng)處理靜態(tài)資源的工作缴渊。簡(jiǎn)單的說(shuō),gulp就是用來(lái)打包項(xiàng)目的鱼炒。
官網(wǎng):https://gulpjs.com/
中文官網(wǎng):https://www.gulpjs.com.cn/docs/
安裝:
全局安裝:
npm i gulp@3.9.1 -g
gulp -v # 測(cè)試是否安裝成功
全局安裝表示在當(dāng)前電腦中可以使用gulp環(huán)境了
局部安裝
npm i gulp@3.9.1 --save-dev # 因?yàn)樵谏暇€后是不需要這個(gè)包的衔沼,所以將這個(gè)項(xiàng)目安裝在開發(fā)依賴
局部安裝表示在當(dāng)前項(xiàng)目要使用的gulp
局部安裝gulp要和全局安裝的gulp版本保持一致
gulp是一個(gè)基于任務(wù)的工具,也就是說(shuō)昔瞧,gulp規(guī)定指蚁,不管做什么功能,都用統(tǒng)一的接口管理自晰,必須去注冊(cè)一個(gè)任務(wù)凝化,然后去執(zhí)行這個(gè)任務(wù),在任務(wù)代碼中缀磕,去做想想做的功能缘圈。這是gulp的特點(diǎn)之一:任務(wù)化。
gulp的每個(gè)功能都是一個(gè)任務(wù)袜蚕,壓縮css的任務(wù)糟把、合并文件的任務(wù)。牲剃。遣疯。gulp規(guī)定任務(wù)要寫在一個(gè)叫做glupfile.js的文件中,在這個(gè)文件中用來(lái)配置所有任務(wù)凿傅。
首先缠犀,gulp和node中的其他模塊一樣数苫,使用的時(shí)候需要引入:
varglup=require("gulp");
這個(gè)gulp是一個(gè)對(duì)象,gulp提供了很多接口辨液,都是這個(gè)對(duì)象的方法虐急。
gulp提供的接口:
注冊(cè)任務(wù)
gulp.task(name[,deps],fn)
參數(shù):
name是任務(wù)名稱,執(zhí)行任務(wù)時(shí)滔迈,使用這個(gè)名稱
fn是一個(gè)回掉函數(shù)止吁,代表這個(gè)任務(wù)要做的事情
例:
gulp.task("print",function(){console.log("打印123");})
執(zhí)行任務(wù):在命令行使用gulp命令,后面跟任務(wù)名稱:
gulp print
如果任務(wù)比較多的話燎悍,一個(gè)一個(gè)來(lái)執(zhí)行敬惦,效率會(huì)很低,所以gulp提供了一個(gè)默認(rèn)任務(wù)谈山,可以將要執(zhí)行的所有任務(wù)放在一個(gè)數(shù)組中俄删,這樣只需要執(zhí)行這個(gè)默認(rèn)任務(wù)就能執(zhí)行數(shù)組中的所有任務(wù):
gulp.task("print1",function(){console.log("打印123");})gulp.task("print3",function(){console.log("打印321");})gulp.task("default",["print1","print3"]);
執(zhí)行默認(rèn)任務(wù):不用寫任務(wù)名
gulp
gulp自己有內(nèi)存,當(dāng)我們使用gulp進(jìn)行項(xiàng)目構(gòu)建的時(shí)候奏路,gulp會(huì)將本地文件數(shù)據(jù)讀取到gulp內(nèi)存中畴椰,接下來(lái)的操作都在內(nèi)存中進(jìn)行,操作完成以后思劳,再?gòu)膅ulp的內(nèi)存中輸出到本地迅矛,比如說(shuō)當(dāng)我們要合并兩個(gè)文件的時(shí)候,先將這兩個(gè)文件中的內(nèi)容讀取到內(nèi)存中潜叛,然后在內(nèi)存中進(jìn)行合并泄隔,最后將合并后的內(nèi)容從內(nèi)存中輸出到本地的文件中塘砸。
這樣吞获,對(duì)應(yīng)著兩個(gè)操作咐汞,一個(gè)是輸入础浮,一個(gè)輸出氧映,也就是I/O操作柜蜈。這是gulp的又一個(gè)特點(diǎn)之一:基于流磨澡。
讀取文件
將本地文件讀取到gulp內(nèi)存中
gulp.src(globs[, options])
參數(shù):
src方法主要是用來(lái)讀取目標(biāo)源文件约谈,所以參數(shù)就是一個(gè)目標(biāo)源文件的路徑
輸出到文件
將內(nèi)存中數(shù)據(jù)輸出到本地文件中
gulp.dest(path[,options])
參數(shù):
dest方法主要用來(lái)將數(shù)據(jù)輸出到文件中笔宿,所以參數(shù)就是目標(biāo)文件路徑。
監(jiān)視文件變化
用來(lái)監(jiān)視某個(gè)或某些文件發(fā)生變化棱诱,可以在變化的時(shí)候泼橘,執(zhí)行一個(gè)回掉函數(shù),以保證文件中的代碼和效果一致
gulp.watch()
gulp插件
我們要處理文件的合并迈勋、壓縮等操作炬灭,接口中沒(méi)有提供,都放在了插件中靡菇。
插件下載:
npm install 插件名 --save-dev
gulp-concat : 合并文件(js/css)
gulp-uglify : 壓縮js文件
gulp-rename : 文件重命名
gulp-less : 編譯less
gulp-sass:編譯sass
gulp-clean-css : 壓縮css
gulp-livereload : 實(shí)時(shí)自動(dòng)編譯刷新
gulp-htmlmin:壓縮html文件
gulp-connect:熱加載重归,配置一個(gè)服務(wù)器
gulp-load-plugins:打包插件(里面包含了其他所有插件)
案例
文件目錄結(jié)構(gòu):
|- dist # 存放目標(biāo)文件|- src # 存放源文件? |- js? |- css? |- less|- index.html|- gulpfile.js-----gulp配置文件
首先在js文件夾下新建test1.js和test2.js米愿,并寫入內(nèi)容
下載多個(gè)插件:
npm install gulp-concat gulp-uglify gulp-rename --save-dev
合并壓縮js
合并這兩個(gè)test文件,并放到dist下的js文件夾下鼻吮,起名叫test.js
// 引入gulpvargulp=require("gulp");// 引入下載好的插件育苟,插件返回的都是方法varconcat=require("gulp-concat");varuglify=require("gulp-uglify");varrename=require("gulp-rename");// 注冊(cè)任務(wù):合并壓縮js的gulp.task("handleJs",function(){returngulp.src("./src/js/*.js")// 找到目標(biāo)源文件,將數(shù)據(jù)讀取到gulp的內(nèi)存中.pipe(concat("test.js"))// pipe是管道的意思椎木,表示將上一步的操作流向下一步违柏,concat在調(diào)用的時(shí)候指定合并后的文件名// 如果要找到j(luò)s文件夾下的所有js文件和子目錄下的js文件,應(yīng)該寫成 gulp.src("./src/js/**/*.js");.pipe(gulp.dest("./dist/js/"));// 輸出內(nèi)容到本地});
使用命令執(zhí)行:
gulp handleJs
繼續(xù)壓縮這個(gè)文件:
// 引入gulpvargulp=require("gulp");// 引入下載好的插件拓哺,插件返回的都是方法varconcat=require("gulp-concat");varuglify=require("gulp-uglify");varrename=require("gulp-rename");// 注冊(cè)任務(wù):合并壓縮js的gulp.task("handleJs",function(){returngulp.src("./src/js/*.js").pipe(concat("test.js")).pipe(gulp.dest("./dist/js/"))// 輸出文件到本地.pipe(uglify())// 壓縮文件.pipe(rename("test.min.js"))// 將壓縮后的文件重命名// 如果要逼格高一點(diǎn)勇垛,使用rename中的對(duì)象? rename({suffix:'.min'}).pipe(gulp.dest("./dist/js"));// 將壓縮后的文件再放到這個(gè)目錄下});
解析sass語(yǔ)法
在sass文件夾下新建test3.scss文件,寫入sass語(yǔ)法士鸥。下載gulp-sass插件
vargulp=require("gulp");varsass=require("gulp-sass");// 解析sass的任務(wù)gulp.task("handleScss",function(){returngulp.src("./src/sass/*.scss").pipe(sass())// 編譯scss文件為css文件闲孤,默認(rèn)編譯后的文件名和原文件名一樣.pipe(gulp.dest("./src/css/"))});
執(zhí)行這個(gè)任務(wù):
gulp handleScss
合并壓縮css
gulp-clean-css插件在使用的時(shí)候,有一個(gè)屬性叫做compatibility烤礁,值為ie8讼积,表示讓這個(gè)css兼容到ie8
vargulp=require("gulp");// 引入下載好的插件,插件返回的都是方法varconcat=require("gulp-concat");varrename=require("gulp-rename");varcleanCss=require("gulp-clean-css");// 合并壓縮css任務(wù)gulp.task("handleCss",function(){returngulp.src("./src/css/*.css").pipe(concat("test.css")).pipe(gulp.dest("./dist/css/")).pipe(cleanCss({compatibility:"ie8"http:// 讓css兼容到ie8})).pipe(rename({suffix:".min"})).pipe(gulp.dest("./dist/css/"))});
每次都是手動(dòng)啟動(dòng)很多任務(wù)脚仔,我們可以將多個(gè)任務(wù)都放在默認(rèn)任務(wù)中勤众,只需要啟動(dòng)默認(rèn)任務(wù)就可運(yùn)行多個(gè)任務(wù)
異步任務(wù)
將多個(gè)任務(wù)放在默認(rèn)任務(wù)中執(zhí)行,
gulp.task('default',['handleJs','handleSass','handleCss']);
然后只要使用gulp命令不用參數(shù)就可以運(yùn)行鲤脏。注意:這樣的寫法在gulp4的版本中格式不支持的们颜,在gulp4中需要用另外的寫法
接下來(lái),將每個(gè)任務(wù)中的return刪掉:
// 引入gulpvargulp=require("gulp");// 引入下載好的插件猎醇,插件返回的都是方法varconcat=require("gulp-concat");varuglify=require("gulp-uglify");varrename=require("gulp-rename");varsass=require("gulp-sass");varcleanCss=require("gulp-clean-css");// 注冊(cè)任務(wù)gulp.task("handleJs",function(){gulp.src("./src/js/*.js")// 找到目標(biāo)源文件窥突,將數(shù)據(jù)讀取到gulp的內(nèi)存中.pipe(concat("test.js"))// pipe是管道的意思,表示將上一步的操作流向下一步硫嘶,concat在調(diào)用的時(shí)候指定合并后的文件名// 如果要找到j(luò)s文件夾下的所有js文件和子目錄下的js文件阻问,應(yīng)該寫成 gulp.src("./src/js/**/*.js");.pipe(gulp.dest("./dist/js/"))// 輸出文件到本地.pipe(uglify())// 壓縮文件.pipe(rename("test.min.js"))// 將壓縮后的文件重命名// 如果要逼格高一點(diǎn),使用rename中的對(duì)象? rename({suffix:'.min'}).pipe(gulp.dest("./dist/js"));// 將壓縮后的文件再放到這個(gè)目錄下});// 解析sass的任務(wù)gulp.task("handleSass",function(){gulp.src("./src/less/*.scss").pipe(less())// 編譯less文件為css文件沦疾,默認(rèn)編譯后的文件名和原文件名一樣.pipe(gulp.dest("./src/css/"))});// 合并壓縮css任務(wù)gulp.task("handleCss",function(){gulp.src("./src/css/*.css").pipe(concat("test.css")).pipe(gulp.dest("./dist/css/")).pipe(cleanCss({compatibility:"ie8"http:// 讓css兼容到ie8})).pipe(rename({suffix:".min"})).pipe(gulp.dest("./dist/css/"))});gulp.task('default',['handleJs','handleSass','handleCss']);
然后繼續(xù)調(diào)用執(zhí)行默認(rèn)任務(wù)
刪掉return的執(zhí)行過(guò)程
將多個(gè)任務(wù)代碼中的return刪掉以后称近,這多個(gè)任務(wù)就是同步的。
起關(guān)鍵性作用是任務(wù)代碼中的return哮塞。return的作用是可以保證任務(wù)是異步執(zhí)行刨秆,還可以保證任務(wù)執(zhí)行完成之后,將gulp內(nèi)存中數(shù)據(jù)清除掉彻桃。
也就是說(shuō)坛善,gulp任務(wù)可以是同步的也可以是異步的。這是gulp的第三個(gè)特點(diǎn):可同步可異步
任務(wù)依賴
上述案例中,css任務(wù)明顯依賴于sass任務(wù)眠屎,但是如果異步執(zhí)行的話剔交,很可能在合并css的時(shí)候,sass還沒(méi)有結(jié)束改衩,那么sass任務(wù)的執(zhí)行完全沒(méi)有了意義岖常,此時(shí),需要在css任務(wù)的task方法中葫督,添加第二個(gè)參數(shù)竭鞍,是一個(gè)數(shù)組,放的是依賴的任務(wù)名稱橄镜。
// 合并壓縮css任務(wù)gulp.task("handleCss",["handleSass"],function(){returngulp.src("./src/css/*.css").pipe(concat("test.css")).pipe(gulp.dest("./dist/css/")).pipe(cleanCss({compatibility:"ie8"http:// 讓css兼容到ie8})).pipe(rename({suffix:".min"})).pipe(gulp.dest("./dist/css/"))});
如果有多個(gè)依賴任務(wù)偎快,都放到第二個(gè)參數(shù)數(shù)組中。這樣可以保證在執(zhí)行當(dāng)前任務(wù)之前洽胶,先執(zhí)行依賴任務(wù)晒夹。
壓縮html
在壓縮html的時(shí)候,gulp-htmlmin方法中有一個(gè)屬性叫collapseWhitespace姊氓,值為true丐怯,表示壓縮掉html中的空格
vargulp=require("gulp");varhtmlmin=require("gulp-htmlmin");// 壓縮htmlgulp.task("handleHtml",function(){returngulp.src("./index.html").pipe(htmlmin({collapseWhitespace:true})).pipe(gulp.dest("./dist/"))});gulp.task('default',['handleJs','handleSass','handleCss',"handleHtml"]);
此時(shí),我們每次對(duì)文件做修改后翔横,都需要手動(dòng)啟動(dòng)任務(wù)读跷,重新進(jìn)行壓縮、合并等操作禾唁,然后手動(dòng)刷新頁(yè)面才能看到改變效览,為了方便,我們可以啟動(dòng)一個(gè)監(jiān)視任務(wù)荡短,每當(dāng)文件發(fā)生變化钦铺, 自動(dòng)啟動(dòng)啟動(dòng)任務(wù),重新進(jìn)行壓縮肢预、合并等操作
半自動(dòng)化構(gòu)建項(xiàng)目
下載插件:
npm install gulp-livereload --save-dev
啟動(dòng)監(jiān)視任務(wù)的時(shí)候,應(yīng)該保證默認(rèn)任務(wù)已經(jīng)啟動(dòng)才能進(jìn)行監(jiān)視洼哎,所以烫映,在watch任務(wù)中應(yīng)該傳入依賴任務(wù)參數(shù)default,任務(wù)代碼中分兩部分內(nèi)容噩峦,首先開啟監(jiān)聽锭沟,然后確認(rèn)監(jiān)聽目標(biāo)文件并綁定相應(yīng)的任務(wù)。這樣就已經(jīng)ok了识补,但是為了安全起見(jiàn)族淮,我們遵循官網(wǎng)的寫法,在每個(gè)被監(jiān)聽的任務(wù)重,添加實(shí)時(shí)刷新的管道
// 監(jiān)視任務(wù)gulp.task("watch",["default"],function(){// 開啟監(jiān)聽livereload.listen();// 確認(rèn)監(jiān)聽的目標(biāo)文件以及綁定相應(yīng)的任務(wù)gulp.watch("./src/js/*.js",["handleJs"]);gulp.watch(["./src/css/*.css","./src/less/*.sass"],["handleCss"]);// 監(jiān)聽多種文件放在數(shù)組中});
執(zhí)行的時(shí)候祝辣,只要執(zhí)行watch任務(wù)就可以贴妻,因?yàn)閣atch任務(wù)不會(huì)退出,會(huì)阻塞在這里進(jìn)行監(jiān)聽蝙斜,且watch有依賴任務(wù)default名惩,會(huì)自動(dòng)幫我們啟動(dòng)默認(rèn)任務(wù)。啟動(dòng)watch任務(wù)后孕荠,每當(dāng)我們修改被監(jiān)聽的任務(wù)娩鹉,系統(tǒng)都會(huì)幫我們重新進(jìn)行壓縮、合并等我們綁定的任務(wù)操作稚伍。
此時(shí)弯予,我們還需要手動(dòng)刷新頁(yè)面,所以个曙,只能算作半自動(dòng)
全自動(dòng)化構(gòu)建項(xiàng)目
下載插件:
npm i gulp-connect --save-dev
根據(jù)插件啟動(dòng)一個(gè)服務(wù)器锈嫩,幫我們自動(dòng)刷新頁(yè)面
// 注冊(cè)全自動(dòng)監(jiān)視任務(wù)gulp.task("server",["default"],function(){// 配置服務(wù)器選項(xiàng)connect.server({root:'./dist/',// 配置服務(wù)器根目錄livereload:true,// 實(shí)時(shí)刷新port:5000// 配置服務(wù)器端口});// 確認(rèn)監(jiān)聽的目標(biāo)文件以及綁定相應(yīng)的任務(wù)gulp.watch("./src/js/*.js",["handleJs"]);gulp.watch(["./src/css/*.css","./src/less/*.scss"],["handleCss"]);// 監(jiān)聽多種文件放在數(shù)組中});
還需要在每個(gè)任務(wù)中添加實(shí)時(shí)刷新設(shè)置:
.pipe(connect.reload())// 將更改后的內(nèi)容實(shí)時(shí)填充到頁(yè)面中
啟動(dòng)這個(gè)任務(wù)后,給我們提供了一個(gè)訪問(wèn)項(xiàng)目的服務(wù)器困檩,只要我們對(duì)內(nèi)容做了修改祠挫,就會(huì)自動(dòng)執(zhí)行任務(wù),且頁(yè)面會(huì)自動(dòng)刷新:
全自動(dòng)任務(wù)啟動(dòng)過(guò)程
如果我們想再省事一點(diǎn)悼沿,不用手動(dòng)打開網(wǎng)頁(yè)等舔,而讓系統(tǒng)自動(dòng)幫我們打開網(wǎng)頁(yè)的話,使用open插件糟趾,自動(dòng)打開鏈接
下載插件:
npm i open --save-dev
在全自動(dòng)任務(wù)下慌植,設(shè)置自動(dòng)打開服務(wù)器鏈接
varopen=require("open");// 注冊(cè)全自動(dòng)監(jiān)視任務(wù)gulp.task("server",["default"],function(){// 配置服務(wù)器選項(xiàng)connect.server({root:'./dist/',// 配置服務(wù)器根目錄livereload:true,// 實(shí)時(shí)刷新port:5000// 配置服務(wù)器端口});// 自動(dòng)打開指定連接open("http://localhost:5000");// 確認(rèn)監(jiān)聽的目標(biāo)文件以及綁定相應(yīng)的任務(wù)gulp.watch("./src/js/*.js",["handleJs"]);gulp.watch(["./src/css/*.css","./src/less/*.scss"],["handleCss"]);// 監(jiān)聽多種文件放在數(shù)組中});
這時(shí)候只要我們啟動(dòng)這個(gè)任務(wù),就會(huì)自動(dòng)幫我們打開網(wǎng)頁(yè)义郑。
擴(kuò)展
所有包
gulp提供了一個(gè)插件蝶柿,可以代替所有插件。也就是說(shuō)只要下載這一個(gè)插件就可以使用其他所有插件了
下載插件:
npm install gulp-load-plugins --save-dev
使用方式:引入以后非驮,是個(gè)函數(shù)交汤,這個(gè)函數(shù)有打包其他插件的代碼,所以一定要調(diào)用這個(gè)函數(shù)劫笙,得到對(duì)象芙扎,這個(gè)對(duì)象中就包含了其他插件的方法,不用再引入其他插件了
var$=require("gulp-load-plugins")();
原來(lái)使用其他插件的時(shí)候填大,都是函數(shù)形式戒洼,使用打包插件的話, 就是將原來(lái)的函數(shù)換成現(xiàn)在這個(gè)對(duì)象的方法允华,一下是修改后的全部代碼:
var$=require("gulp-load-plugins")();vargulp=require("gulp");gulp.task("handleJs",function(){returngulp.src("./src/js/*.js")// 找到目標(biāo)源文件圈浇,將數(shù)據(jù)讀取到gulp的內(nèi)存中.pipe($.concat("test.js")).pipe(gulp.dest("./dist/js/"))// 輸出文件到本地.pipe($.uglify())// 壓縮文件.pipe($.rename("test.min.js")).pipe(gulp.dest("./dist/js")).pipe($.connect.reload())// 將更改后的內(nèi)容實(shí)時(shí)填充到頁(yè)面中});// 解析less的任務(wù)gulp.task("handleSass",function(){returngulp.src("./src/less/*.less").pipe($.less()).pipe(gulp.dest("./src/css/")).pipe($.connect.reload())// 將更改后的內(nèi)容實(shí)時(shí)填充到頁(yè)面中});// 合并壓縮css任務(wù)gulp.task("handleCss",["handleSass"],function(){returngulp.src("./src/css/*.css").pipe($.concat("test.css")).pipe(gulp.dest("./dist/css/")).pipe($.cleanCss({compatibility:"ie8"http:// 讓css兼容到ie8})).pipe($.rename({suffix:".min"})).pipe(gulp.dest("./dist/css/")).pipe($.connect.reload())// 將更改后的內(nèi)容實(shí)時(shí)填充到頁(yè)面中});// 壓縮htmlgulp.task("handleHtml",function(){returngulp.src("./index.html").pipe($.htmlmin({collapseWhitespace:true})).pipe(gulp.dest("./dist/")).pipe($.connect.reload())// 將更改后的內(nèi)容實(shí)時(shí)填充到頁(yè)面中});varopen=require("open");// 注冊(cè)全自動(dòng)監(jiān)視任務(wù)gulp.task("server",["default"],function(){$.connect.server({root:'./dist/',// 配置服務(wù)器根目錄livereload:true,// 實(shí)時(shí)刷新port:5000// 配置服務(wù)器端口});open("http://localhost:5000");gulp.watch("./src/js/*.js",["handleJs"]);gulp.watch(["./src/css/*.css","./src/less/*.less"],["handleCss"]);});gulp.task('default',['handleJs','handleSass','handleCss',"handleHtml"]);
css自動(dòng)添加前綴
目的:將一些不兼容的css屬性添加前綴讓各個(gè)瀏覽器兼容
依賴插件:gulp-autoprefixer
任務(wù)代碼:
vargulp=require("gulp");varprefix=require("gulp-autoprefixer");gulp.task("css",function(){gulp.src("./src/css**").pipe(profix({browsers:["last 5 version","iOS > 3","Firefox > 2","Google > 30"]})).pipe(gulp.dest("./dist/css"));});
會(huì)出現(xiàn)一個(gè)提示寥掐,希望將這個(gè)配置寫在package.json中:
"browsersList":["last 2 version","iOS > 7","Fixefox > 20"]
es6轉(zhuǎn)es5
為了讓更多瀏覽器兼容項(xiàng)目,需要將項(xiàng)目中的es6的語(yǔ)法轉(zhuǎn)為es5的語(yǔ)法磷蜀。
依賴包:
gulp-babel@7.0.1babel-corebabel-preset-es2015
導(dǎo)入的時(shí)候只要導(dǎo)入一個(gè)即可:
const babel = require('gulp-babel')
任務(wù)代碼:
gulp.task('js',function(){returngulp.src('./src/js/**').pipe(babel({presets:['es2015']// 必須要有這個(gè)參數(shù)召耘,否則會(huì)報(bào)錯(cuò)})).pipe(uglify()).pipe(gulp.dest('./dist/js'))})
清除目標(biāo)文件夾
如果每次打包的時(shí)候起不一樣的名字,會(huì)造成有些文件沒(méi)有用蠕搜,但是還占據(jù)空間怎茫。所以每次在打包之前應(yīng)該先將之前的文件夾情空,然后再打包妓灌。
插件:gulp-clean
任務(wù)代碼:
gulp.task('clean',function(){returngulp.src('./dist').pipe(clean())})
Gulp官方插件網(wǎng)站找尋插件轨蛤。(gulp-sass-china)