1. 程式人生 > >gulp+webpack+angular1的一點小經驗(第一部分gulp與webpack的整合)

gulp+webpack+angular1的一點小經驗(第一部分gulp與webpack的整合)

  時間匆匆如流水繼上週熟悉了gulp的初步安裝與環境配置以後,我的專案又進入了新的階段!
  這篇文章將把我這一週遇到的一些問題,以及解決的方式做一個小小的總結,不一定記的完整,但都是個人的一點經驗,分享給大家。有什麼錯誤疏漏還望指正。
  1.angular還是vue?
  這裡我是有很大的猶豫的,最後的結果是angular。這裡有很多私心,這個專案需要技術上的認同,angular作為一個熱門前端框架擁有更大的知名度,這是我選擇angular的一部分原因。另外如果詳細的對比,團隊技術如果從jquery轉型,可以嘗試接觸vue,vue的上手更簡單,這裡不做展開了。
  2.requirejs還是webpack


  最後的決定是用webpack,因為我requirejs要到瀏覽器端去進行程式碼的組織,而webpack在上線之前就把這些做好了,所以效能應該更好。而且webpack可以打包其他型別資源,如css與圖片,雖然我現在不打算用這些功能,但能給我留下一些擴充套件改變的空間。最後requirejs和angular的組合需要引入angular的非同步外掛,這樣讓我望而卻步。而webpack引入angular只需要一句require('angular');當然,這裡邊也有些坑,不過都是後話了。
  3.那麼現在開始整合吧,先從webpack與gulp的整合開始。
  webpack與gulp的整合(當然前提是安裝了webpack,同學們自己去官網檢視安裝嘍),可以通過gulp的一個外掛來做,這個外掛的名字叫gulp-webpack
,名字是不是相當直觀?最簡單的使用方式如下:
  gulp-webpack的npm文件

gulpWebpack = require('gulp-webpack');
...//stream
.pipe(gulpWebpack(require('./webpack.config.js')))
...//stream

  遇到的坑一個(採用配置檔案執行webpack失敗),這個連結裡有詳細的問答: gulp-webpack的坑
  好了,這兩個就配置好了,那麼專案整合angular之前,我們還有一件事沒有做,那就是watch
  對了,watch很重要啊,實時的編譯寫好的程式碼,這樣才能更有效率的搭建框架,編寫程式碼。
  watch的同時,我們還想要把自動快取清理

的機制加進去。從網上查了,gulp的外掛rev配合revCollector可以完成這個任務。這裡有一篇很不錯的文章
  gulp解決專案部署快取
  讀完之後,我們瞭解到,這樣做對於我的伺服器,還不是很完美,因為我沒有靜態資源伺服器啊,而且上面的資源當然也不是永不過期。相反的,如果資源沒用我就希望儘快的刪掉。從網上看了一些,感覺沒有合適我的,於是就需要自己動手刪掉。比如編譯sass,直接使用rev的流程是這樣的:

.pipe(sass.sync().on('error', sass.logError))
.pipe(minifyCss())
.pipe(rename(function(path){
    path.basename=path.basename;
    path.extname = ".css";
}))
.pipe(rev({merge: true}))
.pipe(gulp.dest(distCss))
.pipe(rev.manifest())
.pipe(gulp.dest(distRev+'/css'));

那麼在進入rev步驟之前,我們要把伺服器上已有的檔案刪掉,刪檔案就用del這個命令,需要一個引數,要刪掉的檔案的路徑,我們用這個through2這個命令來獲取gulp流中的檔案路徑,地址稍微手動修改一下,指到編譯結果的資料夾裡:

var gulp = require('gulp'),
    sass = require('gulp-sass'),
    rename = require('gulp-rename'),
    minifyCss = require('gulp-minify-css'),
    debug = require('gulp-debug'),
    rev = require("gulp-rev"),
    revCollector = require("gulp-rev-collector"),
    through = require("through2"),
    del = require("del");

gulp.task('compile-sass',function(){
    return gulp.src('src/scss/*.scss')
    .pipe(changed(distCss,{extension:'.css'}))
    .pipe(debug({title:'debuging:'}))
    .pipe(through.obj(function(chunk,encode,callback){
        var delPath = chunk.cwd+"/"+distCss+"/"+chunk.relative.substring(0,chunk.relative.lastIndexOf("."))+"-*"+".css";
        console.log(delPath);
        del(delPath);
        this.push(chunk);
        callback();
    }))
    .pipe(sass.sync().on('error', sass.logError))
    .pipe(minifyCss())
    .pipe(rename(function(path){
        path.basename=path.basename;
        path.extname = ".css";
    }))
    .pipe(rev({merge: true}))
    .pipe(gulp.dest(distCss))
    .pipe(rev.manifest())
    .pipe(gulp.dest(distRev+'/css'));
});

gulp.task('revCollectorHtml',function(){
    return gulp.src(['webContent/rev/**/*.json','webContent/index.html'])//注意引數是一個數組,用【】包起來的,要不然會報無法給第二個引數建立cwd屬性的錯誤
    .pipe(revCollector({
        replaceReved:true          //一定要加上這一句,不然不會替換掉上一次的值
    }))
    .pipe(gulp.dest(distBase));
});

這樣,watch的任務就變成了:監聽檔案變化,並在變化以後,將rev-collector任務完成。我們採用非同步的策略來做這件事:

var watchScss = gulp.watch('src/scss/*.*',gulpSync.sync([['compile-sass'],'revCollectorHtml']));

我的檔案目錄結構如下:

│  gulpfile.js
│  karma.conf.js
│  package.json
│  webpack.config.js
│
├─node_modules
├─src
│  │  index.html
│  │
│  ├─js
│  │  │  app.js
│  │  │  index.js
│  │  │  router.js
│  │  │
│  │  └─modules
│  │          appUsedetailModule.js
│  │          listsModule.js
│  │          statisticModule.js
│  │
│  ├─scss
│  │      index.scss
│  │
│  └─tpls
│          
│
├─test
│      testIndex.js
│
└─webContent
    │  favicon.ico
    │  index.html
    │
    ├─css
    │      index-5067f89afc.css
    │
    ├─js
    │      bundle-588100fbe5.js
    │
    ├─rev
    │  ├─css
    │  │      rev-manifest.json
    │  │
    │  └─js
    │          rev-manifest.json
    │
    └─tpls

整個gulpfile.js就變成了這樣:

var gulp = require('gulp'),
    sass = require('gulp-sass'),
    rename = require('gulp-rename'),
    minifyCss = require('gulp-minify-css'),
    changed = require('gulp-changed'),
    uglify = require('gulp-uglify'),
    debug = require('gulp-debug'),
    minifyHtml = require('gulp-minify-html'),
    webpack = require("webpack"),
    rev = require("gulp-rev"),
    revCollector = require("gulp-rev-collector"),
    through = require("through2"),
    del = require("del"),
    ngAnnotate = require("gulp-ng-annotate"),
    gulpWebpack = require('gulp-webpack');
var gulpSync = require('gulp-sync')(gulp);


var distCss = 'webContent/css',
    distJs = 'webContent/js',
    distRev = 'webContent/rev',
    distBase = 'webContent';


gulp.task('compile-sass',function(){
    return gulp.src('src/scss/*.scss')
    .pipe(changed(distCss,{extension:'.css'}))
    .pipe(debug({title:'debuging:'}))
    .pipe(through.obj(function(chunk,encode,callback){
        var delPath = chunk.cwd+"/"+distCss+"/"+chunk.relative.substring(0,chunk.relative.lastIndexOf("."))+"-*"+".css";
        console.log(delPath);
        del(delPath);
        this.push(chunk);
        callback();
    }))
    .pipe(sass.sync().on('error', sass.logError))
    .pipe(minifyCss())
    .pipe(rename(function(path){
        path.basename=path.basename;
        path.extname = ".css";
    }))
    .pipe(rev({merge: true}))
    .pipe(gulp.dest(distCss))
    .pipe(rev.manifest())
    .pipe(gulp.dest(distRev+'/css'));
});

gulp.task('compile-js',function(){
    return gulp.src('src/js/**/*.js')
    .pipe(changed(distJs))
    .pipe(debug({title:'debuging js:'}))
    .pipe(through.obj(function(chunk,encode,callback){
        var delPath = chunk.cwd+"/"+distJs+"/bundle-*"+".js";
        console.log(delPath);
        del(delPath);
        this.push(chunk);
        callback();
    }))
    .pipe(gulpWebpack(require('./webpack.config.js')))
    .pipe(ngAnnotate())
    .pipe(uglify())
    .pipe(rev())
    .pipe(gulp.dest(distJs))
    .pipe(rev.manifest())
    .pipe(gulp.dest(distRev+'/js'))
});

gulp.task('compile-html',function(){
    return gulp.src('src/**/*.html')
    .pipe(changed(distBase,{extension:'.html',cwd: ''}))
    .pipe(debug({title:'debuging:'}))
    .pipe(minifyHtml())
    .pipe(rename(function(path){
        path.basename=path.basename;
        path.extname = ".html";
    }))
    .pipe(gulp.dest(distBase));
});

gulp.task('revCollectorHtml',function(){
    return gulp.src(['webContent/rev/**/*.json','webContent/index.html'])//注意引數是一個數組,用【】包起來的,要不然會報無法給第二個引數建立cwd屬性的錯誤
    .pipe(revCollector({
        replaceReved:true          //一定要加上這一句,不然不會替換掉上一次的值
    }))
    .pipe(gulp.dest(distBase));
});

// gulp.task('revCollectorCss',function(){
//  return gulp.src(['webContent/rev/css/*.json','webContent/css/*.css'])
//  .pipe(revCollector({
//      replaceReved:true          //一定要加上這一句,不然不會替換掉上一次的值
//  }))
//  .pipe(gulp.dest(distCss));
// });
function getWatchDelFunc(type){
    return function(event){
        if(event.type==='deleted'){
            var basePath = event.path.substring(0,event.path.lastIndexOf("src"));
            var fileName = event.path.substring(event.path.lastIndexOf("\\")+1,event.path.lastIndexOf("."));
            var delPath = basePath+distCss+"/"+fileName+"-*."+type;
            console.log("watchDelPaths:"+delPath);
            del(delPath);
        }
    }
}

gulp.task('watch',function(){
    var watchScss = gulp.watch('src/scss/*.*',gulpSync.sync([['compile-sass'],'revCollectorHtml']));
    var watchJs = gulp.watch('src/js/**/*.*',gulpSync.sync([['compile-js'],'revCollectorHtml']));
    var watchHtml = gulp.watch('src/**/*.html',gulpSync.sync([['compile-html'],'revCollectorHtml']));
    watchScss.on('change',getWatchDelFunc("css"));
    // watchJs.on('change',getWatchDelFunc("js"));
    watchHtml.on('change',getWatchDelFunc("html"));
});
gulp.task('default',gulpSync.sync([['compile-sass','compile-html','compile-js'],'revCollectorHtml','watch']));

webpack.config.js裡只做了最基本的js編譯:

var webpack = require("webpack");
module.exports = {
    debug: true,
    watch: false,
    entry: "./src/js/index.js",
    output: {
        path: __dirname+'/webContent/js',
        filename: "bundle.js"
    },
    module: {
        loaders: [   
        ]
    },
    resolve: {
    },
    plugins: [
    ]
}