Gulp是什么?
Gulp是前端自動化的工具,但Gulp能用來做什么
1.搭建web服務器
2.使用預處理器Sass,Less
3.壓縮優化,可以壓縮JS CSS Html 圖片
4.自動將更新變化的代碼實時顯示在瀏覽器
5.前端測試
......
這些都不是他的全部功能,社區豐富的插件,為他提供了強大的后盾。
首先下載gulp(前提默認你安裝好了node,先 npm install,創建一個package.json)
npm install gulp -g //全局安裝 npm install gulp --save-dev //本地安裝並加入package.json
一、安裝各種神奇的插件
接下來安裝各種需要的插件:
npm install babel-core babel-preset-es2015 browser-sync gulp gulp-autoprefixer gulp-babel gulp-cache gulp-clean gulp-cssnano gulp-htmlmin gulp-if gulp-imagemin gulp-load-plugins gulp-plumber gulp-sass gulp-size gulp-sourcemaps gulp-uglify gulp-useref gulp-rev-append main-bower-files wiredep --save-dev
各種插件按需求自己選擇,各自功能如下:
1.babel-core babel-preset-es2015 gulp-babel 用於解析es6轉換為es5
2.browser-sync 服務器同步瀏覽
3.gulp-autoprefixer 根據設置瀏覽器版本自動處理瀏覽器前綴
4.gulp-cache 圖片快取,只有更改過得圖片會進行壓縮
5.gulp-clean 清空文件夾
6.gulp-cssnano 壓縮CSS代碼
7.gulp-htmlmin 壓縮html
8.gulp-if 用於判斷
8.gulp-imagemin 圖片壓縮
9.gulp-load-plugins 自動加載(超級有用 省去一大堆代碼)
10.gulp-plumber 管道工 不會讓錯誤爆出來 繼續執行
11.gulp-sass 預編譯Sass
12.gulp-size 統計管道里面內容的大小的,上面是用它來顯示出壓縮前后的大小用來對比用
13.gulp-sourcemaps 當壓縮的JS出錯,能根據這個找到未壓縮代碼的位置 不會一片混亂代碼
14.gulp-uglify JS壓縮
15.gulp-useref 將html引用順序的CSS JS 變成一個文件
例如:<!-- build:js scripts/main.js --> <script src="1.js"></script><script src="2.js"></script><!--endbuild--> 最后變成<script src="main.js"></script>
16.gulp-rev-append html引用添加版本號
17.main-bower-files 找到bower.json里配置的 overrides 下配置的main下的路徑
18.wiredep 在.html文件會把默認bower.json的配置自動注入到下面標簽中去 <!-- bower:js --> <!-- endbower --> <!-- bower:css--> <!-- endbower -->
接下來是用 bower安裝 Jquery bootstrap-sass
bower init //新建bower.json bower install jquery bootstrap-sass --save-dev //安裝jquery bootstrap
二、get Gulp的簡單語法
1.gulp.task(name[,deps],fn)
說明:定義一個gulp任務
name: 類型(必填):String 指定任務的名稱(不應該有空格)
deps:類型(可選):StringArray,該任務依賴的任務(執行name任務要先去執行的任務)
gulp.task('A' , function(){
console.log('A')
});
gulp.task('B' , ['A'] , function(){ //運行B之前先去運行A
console.log('B')
});
fn:類型(必填):Function 該任務調用的插件操作
2.gulp.src(globs[, options])
說明:src方法指定需要處理的源文件路徑,返回當前文件流至可用插件
globs: 類型(必填):String/StringArray 需要處理的源文件匹配符路徑
通配符路徑匹配示例:
“src/a.js”:指定具體文件;
“*”:匹配所有文件 例:src/*.js(包含src下的所有js文件);
“**”:匹配0個或多個子文件夾 例:src/**/*.js(包含src的0個或多個子文件夾下的js文件);
“{}”:匹配多個屬性 例:src/{a,b}.js(包含a.js和b.js文件) src/*.{jpg,png,gif}(src下的所有jpg/png/gif文件);
“!”:排除文件 例:!src/a.js(不包含src下的a.js文件);
options:類型(可選):Object 三個屬性 buffer read base
options.buffer:類型:Boolean 默認:true 設置為false,將返回file.content的流並且不緩沖文件,處理大文件時非常有用;
options.read: 類型:Boolean 默認:true 設置false,將不執行讀取文件操作,返回null;
options.base: 類型:String 設置輸出路徑以某個路徑的某個組成部分為基礎向后拼接
gulp.src('client/js/**/*.js')
.pipe(minify())
.pipe(gulp.dest('build')); // Writes 'build/somedir/somefile.js'
gulp.src('client/js/**/*.js', { base: 'client' })
.pipe(minify())
.pipe(gulp.dest('build')); // Writes 'build/js/somedir/somefile.js'
3.gulp.dest(path[,options])
說明:處理完后文件輸出的路徑
path:類型(必填):String or Function 指定文件輸出路徑,或者定義函數返回文件輸出路徑亦可
options: 類型(可選):Object,有2個屬性cwd、mode;
options.cwd: 類型:String 默認:process.cwd():前腳本的工作目錄的路徑 當文件輸出路徑為相對路徑將會用到;
options.mode: 類型:String 默認:0777 指定被創建文件夾的權限;
4.gulp.watch(glob[,opts],tasks) or gulp.task(glob [,opts ,cd])
說明:watch方法用於監聽文件變化,一被變化就執行指定任務
glob: 需要處理的源文件匹配符路徑。類型(必填):String or StringArray;
opts: 類型(可選):Object 具體參看https://github.com/shama/gaze;
tasks: 類型(必填):StringArray 需要執行的任務的名稱數組;
cb(event): 類型(可選):Function 每個文件變化執行的回調函數;
三、目錄
|--gulp_test |--app //生產文件路徑 |--fonts |--images
|--1.png |--scripts
|--main.js
|--index.js |--styles
|--main.scss
|--index.css |--index.html |--dist //發布文件路徑 |--fonts |--images |--scripts |--styles |--index.html |--bower_components |--bootstrap-sass |--jquery |--node_modules |--各種插件 |--package.json |--bower.json
app是我們新建的目錄和文件夾,其余是按照上面操作自動生成的。
首先在gulp_test下新建.babelrc (用於配置es6 語法) .bowerrc (用於定義bower的路徑)兩個文件
.babelrc
{ "presets": [ "es2015" ] }
.bowerrc
{ "directory": "bower_components" }
設置一下bower.json
{ "name": "gulp_test", "authors": [ "QRL" ], "keywords": [ "bower_components" ], "private": true, "devDependencies": { "jquery": "^3.0.0" }, "overrides": { "bootstrap-sass": { "main": [ "assets/stylesheets/_bootstrap.scss", "assets/fonts/bootstrap/*", "assets/javascripts/bootstrap.js" ] } }, "dependencies": {"bootstrap-sass": "^3.3.6"} }
app下的index.html內容
<!doctype html> <html lang=""> <head> <meta charset="utf-8"> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>test gulp webapp</title> <link rel="apple-touch-icon" href="apple-touch-icon.png"> <!-- Place favicon.ico in the root directory --> <!-- build:css styles/index_main.css --> //這個注釋的意思是 將兩個css合並成一個index_main.css 注意順序 <link rel="stylesheet" href="styles/index.css"> <link rel="stylesheet" href="styles/main.css"> <!-- endbuild --> </head> <body> <div class="container"> <div class="header"> <ul class="nav nav-pills pull-right"> <li class="active"><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> </ul> <h3 class="text-muted">Hello</h3> </div> <div class="jumbotron"> <h1>Hello Gulp!</h1> <p class="lead">Always a pleasure scaffolding your apps.</p> <p><a class="btn btn-lg btn-success" href="#">Splendid!</a></p> </div> <div class="row marketing"> <div class="col-lg-6"> <h4>HTML5 Boilerplate</h4> <p>HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or sites.</p> <h4>Sass</h4> <p>Sass is the most mature, stable, and powerful professional grade CSS extension language in the world.</p> <h4>Bootstrap</h4> <p>Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.</p> <h4>Modernizr</h4> <p>Modernizr is an open-source JavaScript library that helps you build the next generation of HTML5 and CSS3-powered websites.</p> </div> </div> <div class="footer"> <p>♥ from the Yeoman team</p> </div> </div> <!-- Google Analytics: change UA-XXXXX-X to be your site's ID. --> <script> (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]= function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date; e=o.createElement(i);r=o.getElementsByTagName(i)[0]; e.src='https://www.google-analytics.com/analytics.js'; r.parentNode.insertBefore(e,r)}(window,document,'script','ga')); ga('create','UA-XXXXX-X');ga('send','pageview'); </script> <!-- build:js scripts/vendor.js --> //將以下js合並成一個,並更名為vendor.js <script src="/bower_components/jquery/dist/jquery.js"></script> <!-- endbuild --> <!-- build:js scripts/plugins.js --> //注意一下這里 待會會按照順序變成一個plugins.js文件 //是否遇到過這么多的插件引用,Ctrl+c Ctrl+v 還要細致的修改 請留意 wiredep 任務 留意下面的<!-- bower:js --><!-- endbower -->注釋,這可不是隨隨便便的注釋 <!-- bower:js --> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/affix.js"></script> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/alert.js"></script> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/dropdown.js"></script> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/tooltip.js"></script> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/modal.js"></script> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/transition.js"></script> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/button.js"></script> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/popover.js"></script> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/carousel.js"></script> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/scrollspy.js"></script> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/collapse.js"></script> <script src="/bower_components/bootstrap-sass/assets/javascripts/bootstrap/tab.js"></script> <!-- endbower --> <!-- endbuild --> <!-- build:js scripts/index_main.js --> <script src="scripts/index.js"></script> <script src="scripts/main.js"></script> <!-- endbuild --> </body> </html>
接下來最重要了,同樣在gulp_test下新建gulpfile.babel.js(因為這里使用es6,所以需要將原本的gulpfile.js 更名為 gulpfile.babel.js )
四、開始gulp之旅
打開gulpfile.babel.js,開始操作
首先寫進以下代碼:
import gulp from 'gulp'; //引入gulp import gulpLoadPlugins from 'gulp-load-plugins'; //自動加載插件 省去一個一個require進來 import browserSync from 'browser-sync'; //瀏覽器同步 import {stream as wiredep} from 'wiredep'; //把bower 下載的文件引入到html文件中 const $ = gulpLoadPlugins(); const reload = browserSync.reload;
接下來
先嘗試刪除dist文件夾 終端運行 "gulp clean"
gulp.task('clean' , function(){
return gulp.src([
'dist', //刪除dist整個文件夾
'dist/test/**/*', //刪除dist下的test寫任意子文件夾里的文件
'!package.json' //不刪除package.json文件
] ).pipe($.clean());
});
預編譯Sass
gulp.task('styles' , ()=>{
return gulp.src('app/styles/*.scss') //指明源文件路徑 讀取其數據流
.pipe($.plumber()) //替換錯誤的pipe方法 使數據流正常運行
.pipe($.sourcemaps.init()) //壓縮環境出現錯誤能找到未壓縮的錯誤來源
.pipe($.sass.sync({ //預編譯sass
outputStyle: 'expanded', //CSS編譯后的方式
precision: 10,//保留小數點后幾位
includePaths: ['.']
}).on('error', $.sass.logError))
.pipe($.autoprefixer({browsers:['> 1%', 'last 2 versions', 'Firefox ESR']})) //自動匹配瀏覽器支持的后綴
.pipe($.sourcemaps.write('.')) //map文件命名
.pipe(gulp.dest('dist/styles')) //指定輸出路徑
});
../dist/styles目錄下會生成 對應的 *.css 和 *.css.map
轉化es6的JS
gulp.task('scripts' , ()=>{
return gulp.src('app/scripts/**/*.js')
.pipe($.plumber())
.pipe($.sourcemaps.init())
.pipe($.babel()) //靠這個插件編譯
.pipe($.sourcemaps.write('.'))
.pipe(gulp.dest('dist/scripts'));
});
../dist/scripts目錄下會生成 對應的 *.js 和 *.js.map
壓縮圖片
gulp.task('images',()=>{
return gulp.src('app/images/**/*')
.pipe ($.cache ($.imagemin ({ //使用cache只壓縮改變的圖片
optimizationLevel: 3, //壓縮級別
progressive: true,
interlaced: true})
)).pipe (gulp.dest ('dist/images'));
});
通過對比圖片大小,可以看出壓縮了多少
引用字體文件
gulp.task('fonts', () => {
return gulp.src(require('main-bower-files')('**/*. {eot,svg,ttf,woff,woff2}', function (err) {}) //main-bower-files會從bower.json文件里尋找定義好的主要文件路徑
.concat('app/fonts/**/*')) //將bootstrap-sass的fonts和app下我們自己選用的fonts合並起來
.pipe(gulp.dest('dist/fonts')); });
../dist/fonts目錄下會生成 對應的文件
接下來是最最有用的操作,將CSS合並壓縮,JS合並壓縮,html壓縮,加上時間戳避免緩存
gulp.task('html', ['styles' , 'scripts'], ()=>{ //先執行styles scripts任務
var version = (new Date).valueOf() + '';
var options = {
removeComments: false,//清除HTML注釋
collapseWhitespace: true,//壓縮HTML
collapseBooleanAttributes: false,//省略布爾屬性的值 <input checked="true"/> ==> <input />
removeEmptyAttributes: false,//刪除所有空格作屬性值 <input id="" /> ==> <input />
removeScriptTypeAttributes: false,//刪除<script>的type="text/javascript"
removeStyleLinkTypeAttributes: false,//刪除<style>和<link>的type="text/css"
minifyJS: false,//壓縮頁面里的JS
minifyCSS: false//壓縮頁面里的CSS
};
return gulp.src('app/*.html')
.pipe($.plumber())
.pipe($.useref({searchPath: ['app', '.']})) //將頁面上 <!--endbuild--> 根據上下順序合並
.pipe($.if('*.js', $.uglify()))
.pipe($.if('*.css', $.cssnano()))
.pipe($.if('*.html', $.htmlmin(options)))
.pipe($.replace('.js"></script>' , '.js?v=' + version + '"></script>')) //這種方法比較不成熟 每一次的任務都會改變,不管文件是否被修改
.pipe($.replace('.css">' , '.css?v=' + version + '">'))
.pipe(gulp.dest('dist'));
});
查看dist/index.html , 是否還記得

是不是瞬間被嚇到了,再也不用一個個壓縮JS文件,再也不要擔心緩存這種問題,再也不用因為頁面的臃腫而煩惱,幾行配置,一鍵搞定。
優化上面的引用加版本號: 使用插件 gulp-rev-append
import rev from 'gulp-rev-append' gulp.task('html', ['styles' , 'scripts'], ()=>{ //先執行styles scripts任務 return gulp.src('app/*.html') .pipe($.plumber()) .pipe($.useref({searchPath: ['app', '.']})) //將頁面上 <!--endbuild--> 根據上下順序合並 .pipe($.if('*.js', $.uglify())) .pipe($.if('*.css', $.cssnano())) .pipe(rev()) //為引用添加版本號 .pipe($.if('*.html', $.htmlmin(options))) .pipe(gulp.dest('dist')); });
同時需要在index.html的引用后面加上 ?rev=@@hash
<script src="scripts/index.js?rev=@@hash"></script>
添加后的效果
<script src="scripts/index.js?rev=200c90563a2be0adfd8c03f8e4162df7"></script>
最重要是只要app/index.js里不發生改變,這個版本號就不會變化。
接下來再學一個黑魔法——本地建站和自動刷新
gulp.task('serve', ['styles','scripts','fonts'] , ()=>{
browserSync({
notify : false,
port:9000, //端口號
server:{
baseDir:['dist'], //確定根目錄
routes:{
'/bower_components': 'bower_components'
}
}
});
gulp.watch([ //監測文件變化 實行重新加載
'app/*.html',
'app/images/**/*'
]).on('change',reload);
gulp.watch('app/styles/**/*.scss' , ['styles']); //監測變化 執行styles任務
gulp.watch('app/scripts/**/*.js' , ['scripts']);
gulp.watch('app/fonts/**/*' , ['fonts']);
gulp.watch('bower.json' , ['wiredep','fonts']);
});
終端一運行gulp serve 瀏覽器直接打開dist下的index.html,只要一修改監測的文件,瀏覽器立即刷新。
小插曲:接下來解決 wiredep 任務,這個插件主要是用在bower下載文件,方便頁面引用文件
首先在app下新建一個 index_test.html
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <!--bower:css--> <!--endbower--> </head> <body> <p>Hellp wirdep</p> <a href="index.html">dianwo</a> <!-- bower:js --> <!-- endbower --> </body> </html>
然后在gulpfile.babel.js中寫上任務
gulp.task('wiredep_test' , function(){
gulp.src('./app/index_test.html')
.pipe(wiredep({
optional:'configuration',
goes : 'here',
ignorePath:/^(\.\.\/)+/ //生成的路徑忽略../
}))
.pipe(gulp.dest('./app')) //輸出到原路徑
});
然后運行一下,index_test.html 原本的<!-- bower:js --> <!-- endbower --> 變成
<!-- bower:js --> <script src="bower_components/jquery/dist/jquery.js"></script> <script src="bower_components/bootstrap-sass/assets/javascripts/bootstrap.js"></script> <!-- endbower -->
你或許很疑惑這是根據什么自動查找生成的啊?因為沒有中文文檔,自己摸索后是在bower.json里面配置的,review一下剛才的bower.json
"devDependencies": { "jquery": "^3.0.0" }, "overrides": { "bootstrap-sass": { "main": [ "assets/stylesheets/_bootstrap.scss", "assets/fonts/bootstrap/*", "assets/javascripts/bootstrap.js" ] } }, "dependencies": {"bootstrap-sass": "^3.3.6"}
根據以上三個根據,起最大作用的是overrides,最終會根據這些進行生成。
可以稍微測試一下,將bower.json做點小修改 ,增加jquery的選擇
"overrides": { "bootstrap-sass": { "main": [ "assets/stylesheets/_bootstrap.scss", "assets/fonts/bootstrap/*", "assets/javascripts/bootstrap.js" ] }, "jquery" :{ "main":[ "src/*.js" ] } }
回頭看看index_test.html 剛才的jquery.js 被src下的js代替
<!-- bower:js --> <script src="bower_components/modernizr/modernizr.js"></script> <script src="bower_components/jquery/src/ajax.js"></script> <script src="bower_components/jquery/src/attributes.js"></script> <script src="bower_components/jquery/src/callbacks.js"></script> <script src="bower_components/jquery/src/core.js"></script> <script src="bower_components/jquery/src/css.js"></script> <script src="bower_components/jquery/src/data.js"></script> <script src="bower_components/jquery/src/deferred.js"></script> <script src="bower_components/jquery/src/deprecated.js"></script> <script src="bower_components/jquery/src/dimensions.js"></script> <script src="bower_components/jquery/src/effects.js"></script> <script src="bower_components/jquery/src/event.js"></script> <script src="bower_components/jquery/src/jquery.js"></script> <script src="bower_components/jquery/src/manipulation.js"></script> <script src="bower_components/jquery/src/offset.js"></script> <script src="bower_components/jquery/src/queue.js"></script> <script src="bower_components/jquery/src/selector-native.js"></script> <script src="bower_components/jquery/src/selector-sizzle.js"></script> <script src="bower_components/jquery/src/selector.js"></script> <script src="bower_components/jquery/src/serialize.js"></script> <script src="bower_components/jquery/src/traversing.js"></script> <script src="bower_components/jquery/src/wrap.js"></script> <script src="bower_components/bootstrap-sass/assets/javascripts/bootstrap.js"></script> <!-- endbower -->
最后一步,就結束了
gulp.task('build' , ['html' , 'images' , 'fonts'],()=>{
return gulp.src('dist/**/*')
.pipe($.size({title:'build' , gzip:true}));
});
gulp.task('default' ,['clean'],()=>{
gulp.start('build');
});
這就是單獨運行 gulp 就會執行default 然后執行我們想要的操作,同時可以根據size看到壓縮后節省的空間。
感謝您堅持看完,一步步跟着做,你會發現gulp原來辣么容易,前端自動化工具辣么方便。
對於老項目也可以這樣一步一步改造哦!
聲明:上述的 二、get Gulp的簡單語法 摘抄於 Gulp中文網的API文檔 。其余內容均屬樓主一點一滴碼出來的。
