(一)什么是Gulp
gulp是前端開發(fā)過(guò)程中對(duì)代碼進(jìn)行構(gòu)建的工具,它不僅能對(duì)網(wǎng)站資源進(jìn)行優(yōu)化,而且在開發(fā)過(guò)程中很多重復(fù)的任務(wù)能夠使用正確的工具自動(dòng)完成;gulp是基于Nodejs的自動(dòng)任務(wù)運(yùn)行器, 它能自動(dòng)化地完成 javascript/coffee/sass/less/html/image/css 等文件的的測(cè)試、檢查、合并、壓縮、格式化、瀏覽器自動(dòng)刷新、部署文件生成,并監(jiān)聽(tīng)文件在改動(dòng)后重復(fù)指定的這些步驟。在實(shí)現(xiàn)上,它借鑒了Unix操作系統(tǒng)的管道(pipe)思想,前一級(jí)的輸出,直接變成后一級(jí)的輸入,使得在操作上非常簡(jiǎn)單。
(二)Gulp的安裝
首先確保已經(jīng)正確安裝了node.js環(huán)境,然后再以全局方式安裝gulp,一定是全局
npm install -g gulp
全局安裝gulp后,還需要在每個(gè)要使用gulp的項(xiàng)目中都單獨(dú)安裝一次。把目錄切換到你的項(xiàng)目文件夾中,然后在命令行中執(zhí)行:
npm install gulp
為什么全局安裝了gulp,本地還需要安裝?
1.根據(jù)Node開發(fā)團(tuán)隊(duì),本地模塊加載更快;2.Node不考慮全局模塊默認(rèn)情況下使用本地模塊;3.這樣的話可以保證你的項(xiàng)目依賴gulp的版本(或其他依賴)采用的是最初的版本。
為什么本地安裝了gulp,全局還需要安裝?
全局安裝gulp的理由是gulp在你的系統(tǒng)路徑下自動(dòng)執(zhí)行會(huì)比較方便。
(三)gulp的用法
gulp.src()
指定數(shù)據(jù)源文件,產(chǎn)生數(shù)據(jù)流。參數(shù)是文件,可以是數(shù)組
gulp.src(path.src.css.common)
gulp.src(["js/**/*.js",[!js/**/*.min.js]])
gulp.dest()
將管道的輸出寫入文件,同事將這些輸出繼續(xù)輸出,因此可以多次調(diào)用dest方法,將輸出寫入多個(gè)目錄。目錄不存在則新建。
.pipe(gulp.dest(path.dest + "css/"));
gulp.task()
//打包靜態(tài)文件
gulp.task("build",["css","js","html","other"]);
定義一個(gè)任務(wù)build,執(zhí)行三個(gè)子任務(wù)“css”、“js”、“imgs”。這些任務(wù)不是同時(shí)進(jìn)行的,不能認(rèn)為“js”任務(wù)結(jié)束時(shí)“css”任務(wù)已經(jīng)結(jié)束。
如果需要確保一個(gè)任務(wù)在另一個(gè)任務(wù)結(jié)束后執(zhí)行,可將函數(shù)和任務(wù)組合結(jié)合起來(lái)指定依賴關(guān)系。例如:
//執(zhí)行默認(rèn)任務(wù)時(shí) 先執(zhí)行build任務(wù),再執(zhí)行default任務(wù)
gulp.task("default",["build"],function(){
gulp.watch()
//當(dāng)監(jiān)聽(tīng)到文件修改會(huì)觸發(fā)相應(yīng)的任務(wù)事件
gulp.watch(path.src.css,["css"]);
gulp里路徑匹配規(guī)則
使用gulp,僅需知道4個(gè)API即可:gulp.task(),gulp.src(),gulp.dest(),gulp.watch(),
* 匹配文件路徑中的0個(gè)或多個(gè)字符,但不會(huì)匹配路徑分隔符,除非路徑分隔符出現(xiàn)在末尾
** 匹配路徑中的0個(gè)或多個(gè)目錄及其子目錄,需要單獨(dú)出現(xiàn),即它左右不能有其他東西了。如果出現(xiàn)在末尾,也能匹配文件。
? 匹配文件路徑中的一個(gè)字符(不會(huì)匹配路徑分隔符)
[...] 匹配方括號(hào)中出現(xiàn)的字符中的任意一個(gè),當(dāng)方括號(hào)中第一個(gè)字符為^或!時(shí),則表示不匹配方括號(hào)中出現(xiàn)的其他字符中的任意一個(gè),類似js正則表達(dá)式中的用法
* 能匹配 a.js,x.y,abc,abc/,但不能匹配a/b.js
*.* 能匹配 a.js,style.css,a.b,x.y
*/*/*.js 能匹配 a/b/c.js,x/y/z.js,不能匹配a/b.js,a/b/c/d.js
** 能匹配 abc,a/b.js,a/b/c.js,x/y/z,x/y/z/a.b,能用來(lái)匹配所有的目錄和文件
**/*.js 能匹配 foo.js,a/foo.js,a/b/foo.js,a/b/c/foo.js
a/**/z 能匹配 a/z,a/b/z,a/b/c/z,a/d/g/h/j/k/z
a/**b/z 能匹配 a/b/z,a/sb/z,但不能匹配a/x/sb/z,因?yàn)橹挥袉?*單獨(dú)出現(xiàn)才能匹配多級(jí)目錄
?.js 能匹配 a.js,b.js,c.js
a?? 能匹配 a.b,abc,但不能匹配ab/,因?yàn)樗粫?huì)匹配路徑分隔符
[xyz].js 只能匹配 x.js,y.js,z.js,不會(huì)匹配xy.js,xyz.js等,整個(gè)中括號(hào)只代表一個(gè)字符
[^xyz].js 能匹配 a.js,b.js,c.js等,不能匹配x.js,y.js,z.js
nmp 轉(zhuǎn)換cmp 鏡像
npm install -g cnpm --registry=https://registry.npm.taobao.org
(四)Gulp在項(xiàng)目里的應(yīng)用
1.安裝好gulp后,首先要建它的配置文件gulpfile.js,然后放到你的項(xiàng)目目錄中。之后要做的事情就是在gulpfile.js文件中定義我們的任務(wù)了。
2.定義任務(wù)
(1)將項(xiàng)目中需要用到的基于gulp的模塊借助Node下載下來(lái)
例如:添加版本號(hào)的模塊gulp-rev、gulp-rev-collector
? ? ? ? ? ?$ npm install --save gulp-rev
? ? ? ? ? ?$ npm install --save gulp-rev-collector
(2)然后是引入項(xiàng)目
gulp-ng-annotate/gulp-ng-min
這個(gè)插件是ng-annotate的gulp插件版,它解決的是Angular中依賴注入的小問(wèn)題。Angular中通過(guò)參數(shù)名來(lái)進(jìn)行依賴注入,一旦壓縮,參數(shù)名就會(huì)變化導(dǎo)致注入失敗,所以官方推薦通過(guò)添加字符串進(jìn)行注入。代碼如下:
angular.module("MyMod").controller("MyCtrl", ["$scope", "$timeout", function($scope, $timeout) {? }]);
但是一般大家都愿意簡(jiǎn)寫成
angular.module("MyMod").controller("MyCtrl", function($scope, $timeout) {? });
所以gulp-ng-annotate/gulp-ng-min就是負(fù)責(zé)將大家簡(jiǎn)寫的代碼轉(zhuǎn)換成官方推薦的寫法來(lái)保證js壓縮時(shí),注入正常。
gulp-rev
在實(shí)際應(yīng)用gulp-rev的過(guò)程中,盡管你寫好了各個(gè)任務(wù)之間的依賴關(guān)系,任務(wù)執(zhí)行順序也無(wú)誤,可實(shí)際上rev任務(wù)雖然在gulp上顯示執(zhí)行過(guò)了,但因?yàn)橛?jì)算機(jī)機(jī)生成rev-manifest.json還需要時(shí)間,所以當(dāng)gulp執(zhí)行revCollector任務(wù)時(shí),其實(shí)計(jì)算機(jī)還未生成rev-manifest.json。為了保證gulp-rev-collector替換文件成功,解決方法是要在每個(gè)任務(wù)里添加return,確保任務(wù)執(zhí)行完,而不是執(zhí)行過(guò)。或者使用gulp-run-sequence(還未驗(yàn)證)。
gulp-run-sequence
('clean', 'compass', [image', 'style', 'html'],'ftp'),圓括號(hào)里面串行,中括號(hào)里面并行。
var runSequence = require('gulp-run-sequence');
gulp.task('prod', function(cb) {
runSequence('clean', 'compass', ['image', 'style', 'html'], 'ftp', cb);
});
gulp-connect
gulp-connect是開源的,它是一個(gè)靜態(tài)web的服務(wù)(也可以通過(guò)使用gulp-livereload來(lái)定義靜態(tài)web服務(wù))。
a..定義一個(gè)server:
gulp.task('connect', function () {
connect.server({
root:'build',
livereload: true
});
});
其中root是服務(wù)啟動(dòng)的根目錄,換句話說(shuō)別人通過(guò)IP+Port端口訪問(wèn)到你的服務(wù)器所訪問(wèn)到文件夾就是root(這里是'app'),port就是端口了,livereload是一個(gè)標(biāo)志,為true時(shí)gulp會(huì)自動(dòng)檢測(cè)文件的變化然后自動(dòng)進(jìn)行源碼構(gòu)建。
b.啟動(dòng)serve
項(xiàng)目里我通過(guò)用gulp的默認(rèn)任務(wù)來(lái)啟動(dòng)
//定義默認(rèn)任務(wù)
gulp.task('default', ['watch','connect']);
gulp-conact
gulp.task("scripts",function(){
? ? gulp.src(["src/common/reqData.js","src/common/util.js"])
? ? ? ? .pipe(uglify())
? ? ? ? .pipe(concat("base.min.js",{
? ? ? ? ? ? ? ?newLine: "\r\n\r\n"
? ? ? ? ?}))
? ? ? ? .pipe(gulp.dest("min/common"))
});
上例中,將src/common/目錄下reqData.js和util.js壓縮后合并成一個(gè)文件base.min.js,參數(shù)的作用是在兩個(gè)文件之間添加兩個(gè)換行。
(3)配置任務(wù)(我的項(xiàng)目是在轉(zhuǎn)換路徑以后再一次經(jīng)過(guò)gulp來(lái)壓縮,加后綴; )
這里需要注意多個(gè).pipe(rev.manifest())是生成不同的.json文件,所以需要輸出到不同的地方;minJs({mangle:false})參數(shù)的作用是壓縮過(guò)程跳過(guò)函數(shù)名使其不被壓縮。
注意:gulp.src([path.resource,"!./webapp/js/date/**/*.{js,css}","!./webapp/css/news/**/*.{css,eot,svg,ttf,woff}"]) //需要處理的文件,放到一個(gè)字符串?dāng)?shù)組里
(就是將從你的文件里面把所有引用的靜態(tài)資源群不替換掉)