用gulp管理本身的前端開發任務及須要注意的坑

關於gulp,grunt,webpack,剛走前端模塊化的我,真的是傻傻分不清楚,幸虧有大神各類答疑解惑,使我略知一二,你也想知道的,也許還想知道點啥,資源羅列:
一、中文官方文檔
二、阮老師的gulp入門
三、個人參考;
本次開發,受尤大神知乎上的回答提示,沒有采用vue-cli直接入手vue框架,而是採用vue全家桶+requireJs+gulp着手本身的前端構建,gulp爲本身第一次使用,因此寫下此文,算是對本身成長的一次記錄。關於gulp,首先你得知道npm,node這些常識,其次官方的API應該細度加實踐一下,其四個基本操做:gulp.task、gulp.src、gulp.dest、gulp.watch四個基本方法,需用知道是幹什麼的,該怎麼用。gulp有什麼用?文章將基於如下4條逐一展開講:
一、搭建web服務器
二、優化資源,好比壓縮CSS、JavaScript、壓縮圖片;
三、使用預處理器LESS,jade,JSX須要編譯發佈;
四、文件保存時自動重載瀏覽器;javascript

一:開啓一個本地web服務

一般開發時,咱們不可能一直寫靜態頁面,咱們須要在其餘設備查看效果或者與後臺的動態交互,使前端開發變得更有意義。因此與後端交付以前,你得有一個本地服務器來發布你的內容。直白點說,沒有服務器,咱們是經過這樣的連接(file:///D:/vueProject/myblog/dist/index.html)訪問咱們的頁面的,而有了服務器依賴,咱們是經過這樣的連接(http://localhost/)訪問咱們的頁面的,應用上線的感受,有沒有?其實之前基於JavaWeb開發(tomcat)網頁時,根本就沒這檔子事。閒話少扯,進入正題。利用gulp資源,開啓一個服務器,你須要下載安裝gulp-webserver這個插件,而後這樣配置,源碼:css

var gulp = require('gulp');
var webserver = require('gulp-webserver');
gulp.task("Server",function(){
    gulp.src('dist')  //你web資源的根目錄
    .pipe(webserver({
        port:80,
        host:'127.0.0.1',
        liveload:true,
        directoryListing:{
            path:'index.html', //你web資源的起始頁,在dist目錄下
            enable:true
        }
    }))
});

基於以上,而後在命令行中輸入gulp Server就能夠開啓一個本地端口爲80(也能夠爲其餘)的本地服務器,很簡單有木有,但上面的服務器有一個問題,只有本機能訪問,局域網內其餘設備沒法訪問該站點,別信網上那些啥開防火牆,開端口胡扯的,根本不要緊,由於gulp的web-server就只有這點功能,想要服務器局域網都能訪問,在gulp-webserver官方文檔的FAQ給出瞭解決方案:Set 0.0.0.0 as host option.html

二:優化資源

gulp的主要功能就是文件的合併,壓縮,MD5,因爲個人前端JS是基於requireJS構建的,爲了在頁面加載時提升響應速度,就須要減小文件請求數量並壓縮文件的大小,爲了作這些操做,須要下載gulp-requirejs-optimize(requireJS序列化工具),gulp-rename,gulp-concat,gulp-minify-css,gulp-rev,gulp-rev-collector,through2,gulp-clean,run-sequence等插件包。我要達到的目以下圖所示,從新生成發佈目錄、CSS文件的合併壓縮,JS文件的優化及壓縮及重命名帶上MD5序列號。上源碼:圖片描述前端

var gulp = require('gulp'),
reqOptimize =require('gulp-requirejs-optimize'),
rename = require("gulp-rename"),
changed = require("gulp-changed"),
contact =require('gulp-concat'),
rev =require('gulp-rev'),
through2 = require('through2'),
revCollector = require('gulp-rev-collector'),
clean = require('gulp-clean'),
runSequence = require('run-sequence'),
minifyCss = require('gulp-minify-css');
/*將requireJs文件轉移到發佈目錄*/
gulp.task('revJs',function(){
    gulp.src('js/main/*.js')
    .pipe(gulp.dest('dist/js/main'))
});
/*將全部的圖片轉移到發佈目錄*/
gulp.task('revImg',function(){
    gulp.src('img/**/*')
    .pipe(gulp.dest('dist/img'))
});
/*將css文件合併壓縮轉移到發佈目錄*/
gulp.task('revCss',function(){  
     gulp.src('css/*.css')
    .pipe(contact('index.css'))
    .pipe(minifyCss())//{compatibility: 'ie8'}
    .pipe(gulp.dest('dist/css'))
});
/*將主文件依賴管理合並、壓縮、重命名、並去掉.js操做,而後轉移到發佈目錄,操做後文件名如app-1da68b69e1.js*/        
function modify(modifier) {
    return through2.obj(function(file, encoding, done) {
        var content = modifier(String(file.contents));      
        file.contents = new Buffer(content);
        this.push(file);
        done();
    });
}   
function replaceSuffix(data) {
    return data.replace(/\.js/gmi, "");
}    
gulp.task('optimizeJS', function (cb) {
    gulp.src('js/app.js')
    .pipe(reqOptimize({
    optimize:"none",
    paths:{
        vue:'lib/vue',
        vueRouter:'lib/vue-router',
        vueResource:'lib/vue-resource',
        temp:'component/template',
        resize:'component/resizeWindow'
    }
    }))
    .pipe(rev())  //- 文件名加MD5後綴
    .pipe(gulp.dest('dist/js'))   //- 生成MD5後的文件
    .pipe(rev.manifest({merge:true}))  //- 生成一個rev-manifest.json,記錄版本映射
    .pipe(gulp.dest(""))    
    .pipe(modify(replaceSuffix))            //- 對去掉rev-manifest問件中的文件去掉.js後綴,這主要是考慮requireJs的操做規範
    .pipe(gulp.dest(''))       
    .on('end',cb);   
});    
/*因爲對app.js重命名加入了md5序列號值,因此須要替換原始index.html中關於app.js的引用*/
/*這裏須要注意,revCollector()至關於一個全文件查找替換的過程,以個人爲例*/ 
/*個人rev-manifest.json文件中對應的映射是:"app": "app-1da68b69e1",因此這個函數在操做時,會對index.html全文模糊搜索‘app’這三個關鍵字,而後替換爲app-1da68b69e1,*/
/*這其中容易出錯就在於他是模糊搜索,因此若是你的文件中有個css的class名或自定義的標籤名會內容帶有app三個字母,它都會進行替換,因此,在轉換過程當中,要避開這個坑*/      
gulp.task("updateHtml",function (cb) {
    gulp.src(['rev-manifest.json', 'index.html'])  
        .pipe(revCollector())                   //- 替換爲MD5後的文件名
        .pipe(rename("index.html"))
        .pipe(gulp.dest('dist'))
        .on('end', cb);
});

基於以上源碼,在命令行中依次輸入gulp revJs,gulp revImg,gulp revCss, gulp optimizeJS,gulp updateHtml,就能夠達到上述目的,這樣是否是有點繁瑣,能不能一步到位?固然能夠,咱們能夠幫上述任務寫到一個命令中,固然你也能夠寫到default任務中,而後執行gulp alltaskvue

gulp.task('alltask',['revJs','revImg','revCss','optimizeJS','updateHtml'])

上述代碼有一個問題,特別是針對個人項目,由於個人updateHtml是基於optimizeJS執行完後生成的rev-manifest.json執行的,但gulp.task中的任務組,默認是並行執行的,但我但願的是前三個轉移並行執行,後面兩個串行執行,通過資料查找得知,在gulp 4以前,須要依賴run-sequence來管理任務的執行順序,而gulp 4引入了連個新的API:gulp.series(串行)和gulp.parallel(並行)來保證任務按指定的順序執行。在這裏我採用了run-sequence的解決方案:java

gulp.task('default', function(callback) {
    runSequence(
        "clean",                //- 上一次構建的結果清空
        "revImg",
        "revCss",
        "revJs",                
        "optimizeJS",        //- - 文件合併與md5並去.js後綴
        "updateHtml",      //- 首頁路徑替換爲md5後的路徑
        "Server",   //- 服務器開啓
        callback);
});

下一步重點研究,怎樣將生成後的JS及CSS文件帶上如browser-sync-client.js?v=2.18.12版本號的形式。node

四:文件更改保存時瀏覽器的自動重載(先跳過三)

在咱們的開發過程當中,咱們常常會修改html,CSS,js文件,因爲咱們的生產目錄與開發目錄不一致,因此須要執行GULP命令來發布文件到生產目錄。可是頻繁的關閉服務與重啓服務,這樣就形成了不少時間浪費,因此咱們須要利用gulp.watch來監視文件的改動,並將這些改動從新發布到生產目錄,並重啓服務(非手動)。因爲我的以爲gulp-webServer與gulp-livereload的侷限性,因此講服務採用browser-sync來代替gulp-webServer,後者自身支持熱更新,無需在瀏覽器安裝任何插件(gulp-livereload須要安裝livereload插件),直接上源碼:webpack

var browserSync = require("browser-sync").create(); //引入模塊 
/*每次發佈生產文件前,先將dist目錄下的文件狀況*/
gulp.task("clean",function () {
    return gulp.src([
        'rev-manifest.json',
        'dist/js/*.js',
        'dist/index.html'
    ]).pipe(clean());
});   
/*每次app.js變更時,須要清除rev-manifest.json文件中的映射,使其保證只有惟一的一個映射*/
gulp.task("JSreload",function(){
    return gulp.src(['rev-manifest.json', 'dist/js/*.js','dist/index.html']).pipe(clean());
})     
/*每次任務發起前,先清空溫江,而後再依次發佈文件,啓動服務器,監聽變更*/
gulp.task('server', ['clean'], function() {  
    runSequence(       
        "revImg",
        "revCss",
        "revJs",
        "optimizeJS",        //- - 文件合併與md5並去.js後綴
        "updateHtml"      //- 首頁路徑替換爲md5後的路徑
    );      
    browserSync.init({  
        port: 80,  
        server: {  
            baseDir: ['dist']  
        }  
    });  
  //監控文件變化,自動更新 
    gulp.watch('js/app.js', function(){
            runSequence(
            "JSreload",
            'optimizeJS',           
            "updateHtml", 
            browserSync.reload     
        );       
    });  
    gulp.watch('css/*.css',  function(){
            runSequence(
            "revCss",
            browserSync.reload     
        );       
    });
    gulp.watch('index.html',  function(){
            runSequence(
            "updateHtml", 
            browserSync.reload    
        );       
    }); 
});

/將server事務,註冊爲默認任務/
gulp.task('default',['server']);
基於以上操做,命令行運行gulp ,咱們就開啓了一個基於browserSync的本地服務器以下圖所示,而且局域網內的設備均可以經過主機IP+port訪問應用。圖片描述web

三:預處理器文件編譯

暫時沒用到,後面用到再增長,能夠參考其餘人的vue-router

相關文章
相關標籤/搜索