文章同步自個人github
,地址:https://github.com/ireeoo/not...,已於2018年1月17號從新編輯。javascript
提及來用gulp
也有四年多了,以前在sf
上也寫過一篇文章,今天就從新整理下相關的東西,跟你們分享下,長文預警~
__上面這個大可樂就是了__~css
gulp
是一個___基於流式構建___的TaskRunner
,經過gulp
你能夠本身編寫一系列的gulp
任務,組成一個完整的構建系統,幫你完成大部分無聊的工做,這也是構建工具最大的價值 —— 自動化。html
說到gulp
就很難避開grunt
,grunt
是先於gulp
出現的TaskRunner
,只不過gulp
優化了一些功能的實現方式,帶來了不同的思想。前端
先說一下gulp
:vue
gulp
是經過正常的寫代碼而不是配置的方式來實現構建。gulp
採用了unix
的管道思想,把上一級的輸出當作下一級的輸入,把簡單的一些gulp
插件組合起來,解決複雜的問題,每一個插件只負責本身的事情,完成本身的工做以後就把流扔給下一個插件,下一個插件處理完以後再往下傳,如此,直至處理完,而後生成最後的處理結果,整個過程,採用了流式的寫法.gulp
只抽象出了不多的API
,很容易上手。gulp
基於nodejs
的stream
來處理文件,不會產生中間文件,能更快地完成構建。gulp
處理任務:
java
再看看grunt
:node
grunt
中,一切都是基於配置的,在一個大型的構建系統中,你可能會看到比較多的配置項,一堆配置可能看得人頭暈眼花,每一個插件的配置項還不盡相同,用一個插件你就得取熟悉下它的配置,這就很噁心了。grunt
是基於文件系統來構建的,在構建的過程當中會生成中間文件,A
插件處理完的東西不能直接交給B
插件繼續處理,而是採用了迂迴的方式,A
把處理後的扔到C
這個地方,而後B
插件從C
這個地方再去讀取,影響構建速度卻是小事,主要是把事情搞複雜了。聽說grunt
後續的版本可能也會使用stream
這種形式,其實這也不奇怪,看看如今的webpack
,前端時間rollup
以tree-shaking
爲突破口,準備挑戰webpack
,結果webpack
分分鐘就把tree-shaking
的特性給實(chao)現(xi)了,你有的老子都有,你沒有的老子還有,哈哈哈哈,不過grunt好像後知後覺,不知道如今怎麼樣了,很久沒有關注grunt
了。Grunt
處理任務的流程:
jquery
整體來講,我我的以爲gulp
是比grunt
更爲優雅的一種構建工具~,哈哈。webpack
此外,gulp
和grunt
都須要一個構建文件來支持構建,grunt
的是gruntfile.js
,gulp
的是gulpfile.js
經過兩個文件來對比一下:gruntfile.js
文件,我以前項目中的大概是這麼個樣子:git
'use strict'; module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), cssmin: { minify: { expand: true, cwd: 'css/', src: ['*.css', '!*.min.css'], dest: 'css/', ext: '.min.css' }, my_target: { files: [{ expand: true, cwd: '../style/', src: ['*.css', '!*.min.css'], dest: '../build/style/' }] } }, copy: { main: { files: [ { expand: true, cwd: '../views/', src: ['**'], dest: '../build/views/' }, { expand: true, cwd: '../img/', src: ['**'], dest: '../build/img/' }, { expand: true, cwd: '../', src: ['main.html'], dest: '../build/' }, { expand: true, cwd: '../', src: ['*.txt'], dest: '../build/' } ] } }, uglify: { buildall: { files: [{ expand: true, cwd: '../config/', src: '**/*.js', dest: '../build/config/' }, { expand: true, cwd: '../js/controllers/', src: '**/*.js', dest: '../build/js/controllers/' }, { expand: true, cwd: '../js/directive/', src: '**/*.js', dest: '../build/js/directive/' }, { expand: true, cwd: '../js/filter/', src: '**/*.js', dest: '../build/js/filter/' }, { expand: true, cwd: '../js/service/', src: '**/*.js', dest: '../build/js/service/' }] }, builda: { files: { '../build/js/app.js': ['../js/app.js'], '../build/js/libs/bridge.1.1.0.js': ['../js/libs/bridge.1.1.0.js'] } }, release: { files: { '../build/js/libs/libs.min.js': ['../js/libs/zepto.20140520.js', '../js/libs/angular.min.js', '../js/libs/*.js', '!../js/libs/bridge.1.1.0.js', '!../js/libs/libs.min.js'] } } } }); grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.registerTask('default', ['copy', 'cssmin', 'uglify']); };
再來看gulp
的:
var gulp = require('gulp'),//gulp基礎庫 concat = require('gulp-concat'),//合併文件 cssmin = require('gulp-minify-css'),//壓縮css htmlmin = require("gulp-htmlmin"),//壓縮html jsmin = require('gulp-uglify'),//壓縮js rename = require('gulp-rename'),//重命名文件 clean = require("gulp-clean"),//清理目錄 replace = require('gulp-replace'),//文本替換 processhtml = require('gulp-processhtml'),//處理html文件 addsrc = require('gulp-add-src'),//添加額外的文件流 option = { buildPath: "../dist"//構建目錄 }; //構建目錄清理 gulp.task("clean", function (done) { //return cache.clearAll(done); return gulp.src(option.buildPath, { read: false }) .pipe(clean({force: true})); }) gulp.task("imgcopy", function () {//圖片拷貝 gulp.src("../img/**/*") .pipe(gulp.dest(option.buildPath + '/img/')) }) //js文件壓縮 gulp.task('jsmin', function () { gulp.src(["../js/**/**/*.js",'!../js/libs/*.js']) .pipe(jsmin()) .pipe(gulp.dest(option.buildPath+ "/js/")) }); //須要合併和壓縮的文件 gulp.task('concat', function () { gulp.src(['../js/libs/angular.min.js','../js/libs/*.js', '!../js/libs/bridge*.js']) .pipe(concat('libs.min.js')) .pipe(jsmin()) .pipe(addsrc('../js/libs/bridge*.js')) .pipe(jsmin()) .pipe(gulp.dest(option.buildPath + "/js/libs/")) }); gulp.task("processhtml", function () { var date = new Date().getTime(); gulp.src('../main.html') .pipe(replace(/_VERSION_/gi, date)) .pipe(processhtml()) .pipe(htmlmin({ collapseWhitespace: true })) .pipe(gulp.dest(option.buildPath + '/')) }) //壓縮css gulp.task("cssmin", function () { gulp.src("../style/*.css") .pipe(cssmin()) .pipe(gulp.dest(option.buildPath + '/style')) }) //壓縮html文件 gulp.task("htmlmin", function () { gulp.src('../views/**/*.html') .pipe(htmlmin({ collapseWhitespace: true })) .pipe(gulp.dest(option.buildPath + '/views')) }) // 默認任務 清空圖片、樣式、js並重建 運行語句 gulp gulp.task('default', ['clean'], function () { gulp.start('jsmin', 'cssmin', 'processhtml', "htmlmin", 'imgcopy', 'concat'); });
注:上面兩個文件只是拿來作對比說明gulp
和grunt
的書寫方式不一樣,具體的任務二者並不徹底匹配。
IO
如下是一分鐘上手教程:
首先確保你已經正確安裝了nodejs
環境。而後以全局方式安裝gulp
:
npm install -g gulp
全局安裝gulp
後,還須要在每一個要使用gulp
的項目中都單獨安裝一次。把目錄切換到你的項目文件夾中,而後在命令行中執行:
npm install gulp
若是想在安裝的時候把gulp
寫進項目package.json
文件的依賴中,則能夠加上–D
:
npm install -D gulp
在項目根目錄建立gulpfile.js文件
var gulp = require('gulp'); gulp.task('default', function() { console.log('hello world'); });
運行gulp
gulp
默認任務將被運行,向控制檯輸出hello world
。
若是須要運行單個任務, 使用 gulp taskname
命令。
使用gulp
,僅需知道4個API便可:
gulp.task()
gulp.src()
gulp.dest()
gulp.watch()
因此很容易就能掌握。
gulp
處理文件的流程是【讀取文件】、【用插件處理文件】、【輸出文件】,gulp.src()
正式用來讀取要操做的文件的,globs
參數是文件匹配模式(相似正則表達式),用來匹配文件路徑(包括文件名),固然這裏也能夠直接指定某個具體的文件路徑。當有多個匹配模式時,該參數能夠爲一個數組。
gulp
內部使用了node-glob
模塊來實現其文件匹配功能。舉些栗子:
*
匹配文件路徑中的0個或多個字符,但不會匹配路徑分隔符,除非路徑分隔符出如今末尾**
匹配路徑中的0個或多個目錄及其子目錄,須要單獨出現,即它左右不能有其餘東西了。若是出如今末尾,也能匹配文件。?
匹配文件路徑中的一個字符(不會匹配路徑分隔符)[...]
匹配方括號中出現的字符中的任意一個,當方括號中第一個字符爲^或!時,則表示不匹配方括號中出現的其餘字符中的任意一個,相似js正則表達式中的用法!(pattern|pattern|pattern)
匹配任何與括號中給定的任一模式都不匹配的?(pattern|pattern|pattern)
匹配括號中給定的任一模式0次或1次,相似於js正則中的(pattern|pattern|pattern)?
+(pattern|pattern|pattern)
匹配括號中給定的任一模式至少1次,相似於js正則中的(pattern|pattern|pattern)+
*(pattern|pattern|pattern)
匹配括號中給定的任一模式0次或屢次,相似於js正則中的(pattern|pattern|pattern)*@(pattern|pattern|pattern)
匹配括號中給定的任一模式1次,相似於js正則中的(pattern|pattern|pattern)
文件匹配列子:
*
能匹配 reeoo.js
,reeoo.css
,reeoo
,reeoo/
,但不能匹配reeoo/reeoo.js
*.*
能匹配 reeoo.js
,reeoo.css
,reeoo.html
*/*/*.js
能匹配 r/e/o.js
,a/b/c.js
,不能匹配a/b.js
,a/b/c/d.js
**
能匹配 reeoo
,reeoo/reeoo.js
,reeoo/reeoo/reeoo.js
,reeoo/reeoo/reeoo
,reeoo/reeoo/reeoo/reeoo.co
,能用來匹配全部的目錄和文件**/*.js
能匹配 reeoo.js
,reeoo/reeoo.js
,reeoo/reeoo/reeoo.js
,reeoo/reeoo/reeoo/reeoo.js
reeoo/**/co
能匹配 reeoo/co
,reeoo/ooo/co
,reeoo/a/b/co
,reeoo/d/g/h/j/k/co
reeoo/**b/co
能匹配 reeoo/b/co
,reeoo/nb/co
,但不能匹配reeoo/x/nb/co
,由於只有單**
單獨出現才能匹配多級目錄?.js
能匹配 reeoo.js
,reeoo1.js
,reeoo2.js
reeoo??
能匹配 reeoo.co
,reeooco
,但不能匹配reeooco/
,由於它不會匹配路徑分隔符[reo].js
只能匹配 r.js
,e.js
,o.js
,不會匹配re.js
,reo.js
等,整個中括號只表明一個字符[^reo].js
能匹配 a.js
,b.js
,c.js
等,不能匹配r.js
,e.js
,o.js
當有多種匹配模式時可使用數組
//使用數組的方式來匹配多種文件 gulp.src(['js/*.js','css/*.css','*.html'])
使用數組的方式還有一個好處就是能夠很方便的使用排除模式,在數組中的單個匹配模式前加上!
便是排除模式,它會在匹配的結果中排除這個匹配,要注意一點的是【不能在數組中的第一個元素】中使用排除模式,用了也無效!
gulp.src([*.js,'!r*.js'])
匹配全部js
文件,但排除掉r
開頭的js
文件gulp.src(['!r*.js',*.js])
不會排除任何文件,由於排除模式不能出如今數組的第一個元素中
此外,還可使用展開模式。展開模式以花括號做爲定界符,根據它裏面的內容,會展開爲多個模式,最後匹配的結果爲全部展開的模式相加起來獲得的結果。展開的例子以下:
r{e,o}c
會展開爲 rec
,roc
r{e,}o
會展開爲 reo
,ro
r{0..3}o
會展開爲 r0o
,r1do
,r2o
,r3o
options
主要用來配置一些跟文件流相關的額外的信息,主要有三個參數:
默認值是true
,若是設置爲false
,則會覺得stream的方式返回文件內容(file.contents
),而不是buffer
方式,若是對buffer
或者stream
不瞭解,能夠去nodejs
官網看下文檔。
默認值是true
若是設置爲false
,那麼file.contents
會返回空值,也就是並不會去讀取文件,這個值如無需求,最好不要改~
base
的值很神奇,它能夠影響到你插件最終輸出的文件的路徑,默認狀況下,gulp
會根據gulp.src
匹配到的路徑自動設置base
的值,若是你發現這個base知足不了你的需求,就能夠手動指定base
舉個栗子:
// 匹配40017/js/vendor/vue.js,並將base解析成 40017/js gulp.src('40017/js/**/*.js') .pipe(uglify())//壓縮 // 處理完畢的文件,輸出的時候,會用build替換掉base,即輸出文件的路徑爲 build/vendor/vue.js .pipe(gulp.dest('build')); // 手動設置base的值 gulp.src('40017/js/**/*.js', { base: '40017' }) .pipe(uglify())//壓縮 // 處理完畢的文件,輸出的時候,會用build替換掉base,即輸出文件的路徑爲 build/js/vendor/vue.js .pipe(gulp.dest('build'));
和gulp.src
呼應的是gulp.dest()
,這個方法是用來寫文件的,path
爲寫入文件的路徑,options
爲一個可選的參數對象,用了這麼長時間的gulp
,這個參數還真是一次都沒用過,今天就不扯了。
要想使用好gulp.dest()
這個方法,就要理解給它傳入的路徑參數與最終生成的文件的關係。gulp
的使用流程通常是這樣子的:首先經過gulp.src()
方法獲取到咱們想要處理的文件流,而後把文件流經過pipe
方法導入到gulp
的插件中,最後把通過插件處理後的流再經過pipe
方法導入到gulp.dest()
中,gulp.dest()
方法則把流中的內容寫入到文件中,這裏首先須要弄清楚的一點是,咱們給gulp.dest()
傳入的路徑參數,只能用來指定要生成的文件的目錄,而不能指定生成文件的文件名,它生成文件的文件名使用的是導入到它的文件流自身的文件名,因此生成的文件名是由導入到它的文件流決定的,即便咱們給它傳入一個帶有文件名的路徑參數,而後它也會把這個文件名當作是目錄名,例如:
var gulp = require('gulp'); gulp.src('40017/js/vue/vendor.js') .pipe(gulp.dest('dist/vue.js')); //最終生成的文件路徑爲 dist/vue.js/vendor.js,而不是dist/vue.js
要想改變文件名,可使用插件gulp-rename
下面說說生成的文件路徑與咱們給gulp.dest()
方法傳入的路徑參數之間的關係。gulp.dest(path)
生成的文件路徑是咱們傳入的path
參數後面再加上gulp.src()
中有通配符開始出現的那部分路徑。例如:
var gulp = reruire('gulp'); //有通配符開始出現的那部分路徑爲 **/*.js gulp.src('js/**/*.js') .pipe(gulp.dest('dist')); //最後生成的文件路徑爲 dist/**/*.js //若是 **/*.js 匹配到的文件爲 jquery/jquery.js ,則生成的文件路徑爲 dist/jquery/jquery.js
Two more 栗子
gulp.src('js/**/fish.js') //假設匹配到的文件爲js/lib/fish.js .pipe(gulp.dest('dist')); //則最後生成的文件路徑爲 dist/lib/fish.js gulp.src('js/*') //有通配符出現的那部分路徑爲 * //假設匹配到的文件爲js/4in1.js .pipe(gulp.dest('dist')); //則最後生成的文件路徑爲 dist/4in1.js
gulp.src('js/vue/vendor.js') //沒有通配符出現的狀況 .pipe(gulp.dest('dist')); //最後生成的文件路徑爲 dist/vendor.js
經過指定gulp.src()
方法配置參數中的base
屬性,咱們能夠更靈活的來改變gulp.dest()
生成的文件路徑(前面已經說過)。
當咱們沒有在gulp.src()
方法中配置base
屬性時,base
的默認值爲通配符開始出現以前那部分路徑,例如:
gulp.src('src/js/**/*.js') //此時base的值爲 src/js
上面咱們說的gulp.dest()
所生成的文件路徑的規則,其實也能夠理解成,用咱們給gulp.dest()
傳入的路徑替換掉gulp.src()
中的base
路徑,最終獲得生成文件的路徑。
gulp.src('src/js/**/*.js') //此時base的值爲src/js,也就是說它的base路徑爲src/js //設該模式匹配到了文件 src/js/common/common.js .pipe(gulp.dest('dist')) //用dist替換掉base路徑,最終獲得 dist/common/common.js
因此改變base
路徑後,gulp.dest()
生成的文件路徑也會改變,這個前面說過了,這裏就不贅述了。
用gulp.dest()
把文件流寫入文件後,若是還有後續操做的話,文件流仍然能夠繼續使用。
gulp.task
方法用來定義任務,name
爲任務名,deps
是當前定義的任務須要依賴的其餘任務列表,
爲一個數組。當前定義的任務會在全部依賴的任務執行完畢後纔開始執行。
若是沒有依賴,則可省略這個參數,fn
爲具體的任務函數,咱們把任務要執行的代碼都寫在裏面。該參數也是可選的。
栗子(HTML
壓縮):
let gulp = require("gulp"); let htmlmin = require("gulp-htmlmin"); gulp.task("htmlmin",()=>{ gulp.src("src/**/*.html") .pipe(htmlmin({ collapseWhitespace: true, removeComments: true, //清除HTML註釋 collapseBooleanAttributes: true, //省略布爾屬性的值 <input checked="true"/> ==> <input /> removeScriptTypeAttributes: true, //刪除<script>的type="text/javascript" removeStyleLinkTypeAttributes: true, //刪除<style>和<link>的type="text/css" minifyJS: true, //壓縮頁面JS minifyCSS: true //壓縮頁面CSS }))) .pipe(gulp.dest("dist")) })
gulp.watch()
用來監視文件的變化,當文件發生變化後,咱們能夠利用它來執行相應的任務,例如文件壓縮等,這樣就不須要在文件改變的時候,手動去執行任務了。glob
爲要監視的文件匹配模式,規則和用法與gulp.src()
方法中的glob相同,再也不贅述。opts
爲一個可選的配置對象,一般不須要用到,略過。tasks
爲文件變化後要執行的任務,爲一個數組,一個或者多個經過 gulp.task()
建立的 task
的名字的列表。
gulp.task('uglify',function(){ //do something }); gulp.task('reload',function(){ //do something }); gulp.watch('js/**/*.js', ['uglify','reload']);//在js文件發生變化的時候執行uglify和reload兩個任務
gulp.watch()
還有另一種使用形式:
gulp.watch(glob[, opts, cb])
glob
和opts
參數略過,這裏跟上面的那種方式惟一不一樣的地方就是第三個參數了,cb
參數爲一個函數。每當監視的文件發生變化時,就會調用這個函數,而且會給它傳入一個對象,該對象包含了文件變化的一些信息,type
屬性爲變化的類型,能夠是added
,changed
,deleted
,path
屬性爲發生變化的文件的路徑
gulp.watch('js/**/*.js', function(event){ console.log(event.type); //變化類型 added爲新增,deleted爲刪除,changed爲改變 console.log(event.path); //變化的文件的路徑 });
OK,gulp
的Api
就介紹這麼多了,是否是很簡單?
使用gulp-uglify
安裝:npm install --save-dev gulp-uglify
用來壓縮js
文件,使用的是UglifyJs
引擎
var gulp = require('gulp'), uglify = require("gulp-uglify"); gulp.task('minify-js', function () { gulp.src('js/*.js') // 要壓縮的js文件 .pipe(uglify()) .pipe(gulp.dest('dist/js')); //壓縮後的路徑 });
使用gulp-rename
安裝:npm install --save-dev gulp-rename
用來重命名文件流中的文件。用gulp.dest()
方法寫入文件時,文件名使用的是文件流中的文件名,若是要想改變文件名,那能夠在以前用gulp-rename
插件來改變文件流中的文件名。
var gulp = require('gulp'), rename = require('gulp-rename'), uglify = require("gulp-uglify"); gulp.task('rename', function () { gulp.src('js/vue.js') .pipe(uglify()) //壓縮 .pipe(rename('vue.min.js')) //vue.js重命名爲vue.min.js .pipe(gulp.dest('js')); });
以前的壓縮插件gulp-minify-css已經廢棄
如今推薦使用的是gulp-clean-css
安裝:npm install gulp-clean-css --save-dev
栗子:
var gulp = require('gulp'), cleanCSS = require("gulp-clean-css"); gulp.task('minify-css', function () { gulp.src('css/*.css') // 要壓縮的css文件 .pipe(cleanCSS()) //壓縮css .pipe(gulp.dest('dist/css')); });
使用gulp-minify-html
安裝:npm install --save-dev gulp-minify-html
var gulp = require('gulp'), minifyHtml = require("gulp-minify-html"); gulp.task('minify-html', function () { gulp.src('html/*.html') // 要壓縮的html文件 .pipe(minifyHtml()) //壓縮 .pipe(gulp.dest('dist/html')); });
使用gulp-concat
安裝:npm install --save-dev gulp-concat
用來把多個文件合併爲一個文件,咱們能夠用它來合併js
或css
文件等,這樣就能減小頁面的http
請求數。
var gulp = require('gulp'), concat = require("gulp-concat"); gulp.task('concat', function () { gulp.src('js/*.js') //要合併的文件 .pipe(concat('all.js')) // 合併匹配到的js文件並命名爲 "all.js" .pipe(gulp.dest('dist/js')); });
使用gulp-processhtml
安裝:npm install --save-dev gulp-processhtml
在構建時處理按你設想的修改html
文件,好比說你構建以前你有N
個腳本須要引入到html
頁面中,構建以後可能這N
個文件被合併成了一個,這時候引入的地方也須要作相應的調整,那麼差個插件就能派上用場了。
插件使用
gulp.task("processhtml", function () { gulp.src('../main.html') .pipe(processhtml()) .pipe(gulp.dest("dist")) })
main.html
構建以前的代碼
<!DOCTYPE html> <html ng-app="app"> <head lang="en"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/> <meta name="format-detection" content="telephone=no"/> <link rel="stylesheet" href="style/base.css?/> <link rel="stylesheet" href="style/index.css?/> </head> <body> <ui-view></ui-view> </body> <!-- build:js js/libs/libs.min.js --> <!--process-html插件須要用到這個註釋-- > <script src="js/libs/angular.min.js"></script> <script src="js/libs/angular.touch.min.js"></script> <script src="js/libs/zepto.20140520.js"></script> <script src="js/libs/angular.ui.bootstrap.js"></script> <script src="js/libs/angular-sanitize.min.js"></script> <script src="js/libs/angular-ui-route.min.js"></script> <script src="js/libs/fastclick.0.6.7.min.js"></script> <script src="js/libs/carous.min.js"></script> <!-- /build --> <!--process-html插件須要用到這個註釋--> </html>
main.html
構建以後
<!DOCTYPE html> <html ng-app="app"> <head lang="en"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/> <meta name="format-detection" content="telephone=no"/> <link rel="stylesheet" href="style/base.css?/> <link rel="stylesheet" href="style/index.css?/> </head> <body> <ui-view></ui-view> </body> <script src="js/libs/libs.min.js"></script> <!--注意這裏的變化--> </html>
使用gulp-replace
安裝:npm install --save-dev gulp-replace
能夠替換html或者txt等文件內的字符串爲你想要的。
好比我每次構建的時候都須要去修改引用的文件的版本號,就可使用這個插件
gulp.task("replace", function () { var date = new Date().getTime(); gulp.src('../main.html') .pipe(replace(/_VERSION_/gi, date)) .pipe(gulp.dest("dist")) })
main.html
文件
<!DOCTYPE html> <html ng-app="app"> <head lang="en"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/> <meta name="format-detection" content="telephone=no"/> <link rel="stylesheet" href="style/base.css?v=_VERSION_"/> <link rel="stylesheet" href="style/index.css?v=_VERSION_"/> </head> <body> <ui-view></ui-view> </body> <script src="js/config/config.js?v=_VERSION_"></script> <script src="js/app.js?v=_VERSION_"></script> <script src="js/service/TrackDataService.js?v=_VERSION_"></script> <script src="js/service/APIService.js?v=_VERSION_"></script> <script src="js/service/DService.js?v=_VERSION_"></script> <script src="js/controllers/indexCtrl.js?v=_VERSION_"></script> <script src="js/directive/lazy.js?v=_VERSION_"></script> <script src="js/directive/slider.js?v=_VERSION_"></script> <script src="js/filter/filters.js?v=_VERSION_"></script> </html>
構建以後,_VERSION_
被替換爲時間戳。
<!DOCTYPE html> <html ng-app="app"> <head lang="en"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/> <meta name="format-detection" content="telephone=no"/> <link rel="stylesheet" href="style/base.css?v=1433405631860"/> <link rel="stylesheet" href="style/index.css?v=1433405631860"/> </head> <body> <ui-view></ui-view> </body> <script src="js/config/config.js?v=1433405631860"></script> <script src="js/app.js?v=1433405631860"></script> <script src="js/service/TrackDataService.js?v=1433405631860"></script> <script src="js/service/APIService.js?v=1433405631860"></script> <script src="js/service/DService.js?v=1433405631860"></script> <script src="js/controllers/indexCtrl.js?v=1433405631860"></script> <script src="js/directive/lazy.js?v=1433405631860"></script> <script src="js/directive/slider.js?v=1433405631860"></script> <script src="js/filter/filters.js?v=1433405631860"></script> </html>
用gulp-bytediff這個插件,你能夠看到gulp
處理先後文件的大小變化。
栗子:
let uglify = require("gulp-uglify"); let util = require("gulp-util"); let bytediff = require("gulp-bytediff"); function bytediffFormatter(data){ let difference = (data.savings > 0) ? ' smaller.' : ' larger.', result = data.savings > 0 ? ('and is ' + util.colors.yellow.bold(~~((1 - data.percent) * 100) + '%') + difference) : ""; return `${util.colors.cyan.bold(data.fileName)} from ${util.colors.yellow.bold((data.startSize / 1000).toFixed(2))} kB to ${util.colors.yellow.bold((data.endSize / 1000).toFixed(2))} kB ${result}`; } gulp.task("bd",()=>{ gulp.src("src/js/**/*.js") .pipe(bytediff.start()) .pipe(uglify()) .pipe(bytediff.stop(bytediffFormatter)) .pipe(gulp.dest("dist")) })
console會輸出以下信息:
因爲gulp
執行的多個任務的時候,任務之間彼此是異步的,不能確保執行順訊,這個插件可讓一系列的任務按順序執行。
安裝
npm install --save-dev gulp-sequence
使用:
var gulp = require('gulp') var gulpSequence = require('gulp-sequence') gulp.task('a', function (cb) { //doSomething }) gulp.task('b', function (cb) { //doSomething }) gulp.task('c', function (cb) { //doSomething }) gulp.task('d', function () { // return stream return gulp.src('js/**/*.js') }) // 1. 並行執行a、b; // 2. 執行完a、b以後執行c; // 3. 執行完c以後,執行d; gulp.task('default', gulpSequence(['a', 'b'], 'c', 'd'))
能夠結合browser-sync和gulp.watch()
作多終端自動刷新,只要文件發生變化,就能夠自動構建,而後瀏覽器自動刷新代碼,相似於webpack
的熱替換。
安裝:npm i browser-sync -D
栗子:
const browserSync = require("browser-sync"); const uglify = require("gulp-uglify"); const sequence = require("gulp-sequence");//按順序執行 gulp.task("uglify",()=>{ return gulp.src('js/**/*js') .pipe(uglify()) .pipe(gulp.dest('dist')); }) gulp.task('watch', () => { const watcher = gulp.watch("js/**/*.js", ["uglify"]); wathcer.on('change', function (path) { browserSync.reload(); }) }) gulp.task('server', () => { //靜態服務器 browserSync({ server: { baseDir: `dist` //從這個項目的dist目錄啓動服務器 }, open: "external",//Browsersync啓動時自動打開外部網址,也就是咱們的本地IP加端口 logConnections: true, // directory: true,//是否列出目錄 startPath: "/main.html",//服務器啓動以後默認訪問哪一個頁面 }); }) gulp.task("default",sequence(['uglify'], ['server'], ['watch']))
上面說到的插件都是用commonjs
的方式手動引入的,好比 let bs = require("browser-sync")
,使用gulp-load-plugins這個插件,能夠自動地從依賴文件中提取插件並注入到你想要的對象中,無需手動引入。
插件安裝:
npm install --save-dev gulp-load-plugins
栗子:
let $ = require('gulp-load-plugins')({//初始化各類插件引用 pattern: ['gulp-*', 'imagemin-pngquant', 'browser-sync'],//搜索插件的正則 replaceString: /\bgulp[\-.]/,//當把插件加載到執行環境的時候,去除哪些文本 lazy: true,//是否懶加載插件,true,只有用到的時候纔去加載,false反之 camelize: true//設置爲true則插件被加載進來的時候名稱是駝峯形式的 })
好比以前安裝了gulp-clean-css
的插件,那麼如今這須要這麼用:
var gulp = require('gulp'), //cleanCSS = require("gulp-clean-css");這個就不用了 //gulp-load-plugins會根據搜索的正則去找gulp-clean-css這個插件,並把它名字前面的gulp去掉,而後把剩下的轉成駝峯`cleanCss`,這就是待會要使用的插件的方法名字了,這個方法是掛在前面已經定義好的對象$上的,因此能夠直接$.cleanCss()這樣去調用。 gulp.task('minify-css', function () { gulp.src('css/*.css') // 要壓縮的css文件 .pipe($.cleanCSS()) //壓縮css .pipe(gulp.dest('dist/css')); });
其餘的插件使用方式大同小異。
上面只介紹了gulp-load-plugins
一些經常使用的參數,其餘的參數你們能夠去npm
查看。
gulp
還有不少插件,你們能夠去gulp官網查看
有人會說,webpack
都一統天下了,你怎麼還在折騰gulp
?
大多數人都以爲webpack
是目前前端工程化完整性解決方案,無論你什麼grunt
仍是gulp
都得給我靠邊站,只要使用webpack
就足夠了。
真的是這樣嗎???
webpack
官網給自身的定位是webpack is a module bundler
,也就是說,webpack
是模塊打包器,webpack
的競爭對手應該是browserify
之流,而不是gulp
或是grunt
這類Task Runner
。
我記得以前webpack
官方也給出了gulp
中使用webpack
的方式(webpack1.x的文檔已經被刪了,找不到了,呵呵)
雖然webpack
能夠替代gulp的一些功能,可是我不以爲這二者是非此即彼的狀態,工具只選合適的。
來,乾了這杯大可樂~
如對
gulp
還有什麼不明白之處,或者本文有什麼遺漏或錯誤,歡迎一塊兒交流。