關於gulp中自動添加版本號及Html文件應用路徑替換的問題

最近項目作了一段時間了,爲了測試的準確性及節約更多的時間,咱們須要將前端中靜態資源的引用加上hash版本號,以方便測試在工做時不用總是去清理緩存,由於項目工程原本就使用了Gulp,因此就在gulpfile.js中加入了gulp-revgulp-rev-collector兩個插件來實現這個目的。css

最開始的時候還算順利,不過在測試的時候發現問題,執行任務命令後,只在第一次自動替換了html中的資源連接,而當咱們修改了源文件以後,就不行了,貌似找不到須要替換的關鍵字,因此有了下面的解決方案。html

咱們先來看看原來加上版本號是什麼樣的前端

"/css/style.css" => "/dist/css/style-1d87bebe.css"
"/js/script1.js" => "/dist/script1-61e0be79.js"
"cdn/image.gif"  => "//cdn8.example.dot/img/image-35c3af8134.gif"

而如今咱們須要改爲這樣:node

"activity/channel/2.css": "activity/channel/2.css?v=4ddaaeae28"
"activity/christmas.css": "activity/christmas.css?v=2d21a0c7ca"
"activity/channel/1.jpg": "activity/channel/1.jpg?v=c8571d8112"

因此,咱們如今須要手動更改兩個插件的源碼:chrome

第一步:打開node_modules\gulp-rev\index.js 第144行npm

/*manifest[originalFile] = revisionedFile;*/
manifest[originalFile] = originalFile + '?v=' + file.revHash;

第二步:打開node_modules\rev-path\index.js 第10行json

/*return filename + '-' + hash + ext;*/
return filename + ext;

注意:這一步中,不少同窗找不到這個rev-path,是由於之前的gulp-rev插件將這部分集成在了裏面,然後續的版本將rev-pathgulp-rev裏抽離出來了,因此要在項目目錄的node_modules裏找這個插件,固然,咱們不須要手動安裝,這是gulp-rev的依賴,npm會自動安裝它。gulp

第三步:打開node_modules\gulp-rev-collector\index.js 第31行瀏覽器

/*if ( !_.isString(json[key]) || path.basename(json[key]).replace(new RegExp( opts.revSuffix ), '' ) !==  path.basename(key) ) {
          isRev = 0;
  }*/
 
  if ( !_.isString(json[key]) || path.basename(json[key]).split('?')[0] !== path.basename(key) ) {
          isRev = 0;
  }

第50行緩存

/*return pattern.replace(/[\-\[\]\{\}\(\)\*\+\?\.\^\$\|\/\\]/g, "\\$&");*/
var rp = pattern.replace(/[\-\[\]\{\}\(\)\*\+\?\.\^\$\|\/\\]/g, "\\$&");
rp = pattern + "(\\?v=(\\d|[a-z]){8,10})*";
return rp;

第90行

/*patterns.push( escPathPattern( (path.dirname(key) === '.' ? '' : closeDirBySep(path.dirname(key)) ) + path.basename(key, path.extname(key)) )
                            + opts.revSuffix
                            + escPathPattern( path.extname(key) )
                        );*/
 
 patterns.push( escPathPattern( (path.dirname(key) === '.' ? '' : closeDirBySep(path.dirname(key)) ) + path.basename(key, path.extname(key)) )
                            + opts.revSuffix
                            + escPathPattern( path.extname(key) ) + "(\\?v=(\\d|[a-z]){8,10})*"
                        );

OK,這樣就可使用gulpfile.js裏定義的任務了,下面是個人gulpfile.js

/* 載入模塊 */
var gulp = require('gulp'),
    less = require('gulp-less'),
    mincss = require('gulp-minify-css'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    clean = require('gulp-clean'),
    browerify = require('browserify'),
    sourcemaps = require('gulp-sourcemaps'),
    source = require('vinyl-source-stream'),
    buffer = require('vinyl-buffer'),
    replace = require('gulp-str-replace'),
    imagemin = require('gulp-imagemin'),
    browserSync = require('browser-sync'),
    rev = require('gulp-rev'),                          // 爲靜態資源文件替換帶MD5的文件名
    revCollector = require('gulp-rev-collector'),       // 替換靜態資源連接
    runSequence = require('run-sequence');         // 順序執行

/* 自動刷新 start */
gulp.task('browser', function () {
  return browserSync({
    port: 3000,
    open: true,
    startPath: '/',
    server: {
      directory: true,
      routes: {
        '/': '/'
      },
      middleware: function (req, res, next) {
        console.log('middleWare.');
        next();
      },
      baseDir: './'
    },
    //指定瀏覽器
    browser: 'chrome',
    //延遲刷新,默認爲0
    reloadDelay: 1,
    //是否載入css修改,默認true
    injectChanges: true
  });
});

gulp.task('bro', function () {
  return gulp.src('./src/*')
             .pipe(browserSync.reload({
                stream: true
              }));
});
/* 自動刷新 end */

var fs = require('fs');
var fileContent = fs.readFileSync('./package.json');
var jsonObj = JSON.parse(fileContent);

var argv = process.argv.pop();
var DEBUGGER = (argv === '-D' || argv === '-d') ? true : false;

/* 基礎路徑 */
var paths = {
  css       :  'src/common/css/',
  less      :  'src/less/',
  scripts   :  "src/js/",
  img       :  "src/images/",
  html      :  "src/html/",
  build     :  "src/build/",
  src       :  'src/'
};

/* 項目資源文件目錄 */
var cssSrc = paths.src + 'css/block_css/*.css',
    jsSrc = paths.src + 'angular/modules/**/*.js';

if(DEBUGGER) {
    resProxy = "http://localhost:3000/build";
    prefix = "http://localhost:3000/build";
}

/* 清理css文件 */
gulp.task('clean-css', function () {
  return gulp.src([paths.build + "css/*.css", paths.src + "css/style.min.css"])
             .pipe(clean());
});

/* 清理js文件 */
gulp.task('clean-js', function () {
  return gulp.src([paths.build + "js/*.js"])
             .pipe(clean());
});

/* 編譯LESS */
gulp.task('runLess', ['clean-css'], function () {
  return gulp.src([paths.less + '**/*.less', paths.css + '**/*.css'])
           .pipe(less())
           .pipe(concat('main.min.css'))
           .pipe(mincss())
           .pipe(replace({
                      original : {
                        resProxy : /\@{3}RESPREFIX\@{3}/g,
                        prefix : /\@{3}PREFIX\@{3}/g
                      },
                      target : {
                        resProxy : resProxy,
                        prefix : prefix
                      }
                  }))
           .pipe(gulp.dest(paths.build + "/css"))
           .pipe(browserSync.reload({stream:true}));
});

/* 合併、壓縮CSS */
gulp.task('handleCss', ['clean-css'], function () {
  return gulp.src([paths.src + 'css/block_css/*.css'])
             .pipe(concat('style.min.css'))
             .pipe(mincss())
             .pipe(gulp.dest('./src/css'))
             .pipe(rev())
             .pipe(gulp.dest(paths.build + 'css'))
             .pipe(rev.manifest())
             .pipe(gulp.dest('./rev/css'));
});

/* 合併、壓縮 JS */
gulp.task('handleJs', ['clean-js'], function () {
  return gulp.src([paths.src + 'angular/app.js', paths.src + 'angular/modules/**/*.js'])
             .pipe(concat('app.min.js'))
             .pipe(uglify())
             .pipe(rev())
             .pipe(gulp.dest(paths.build + 'js'))
             .pipe(rev.manifest())
             .pipe(gulp.dest('./rev/js'));
});

/* CSS生成文件hash編碼並生成 rev-manifest.json文件名對照映射 */
// gulp.task('revCss', ['handleCss'], function(){
//     return gulp.src('./src/css/style.min.css')
//                .pipe(rev())
//                .pipe(gulp.dest(paths.src + 'build/css'))
//                .pipe(rev.manifest())
//                .pipe(gulp.dest(paths.src + 'rev/css'));
// });

/* js生成文件hash編碼並生成 rev-manifest.json文件名對照映射 */
// gulp.task('revJs', function(){
//     return gulp.src(jsSrc)
//         .pipe(rev())
//         .pipe(rev.manifest())
//         .pipe(gulp.dest('rev/js'));
// });


//Html替換css、js文件版本
gulp.task('revHtml', function () {
    return gulp.src(['./rev/**/*.json', './src/*.html'])
               .pipe(revCollector())
               .pipe(gulp.dest('./src'));
});

// 處理manage目錄中的連接替換
gulp.task('revManageHtml', function () {
  return gulp.src(['./rev/**/*.json', './src/manage/*.html'])
             .pipe(revCollector())
             .pipe(gulp.dest('./src/manage'));
});


/* 監聽HTML文件變化 */
gulp.task('html', function () {
  return gulp.src(paths.html + "**/*.html")
        .pipe(replace({
            original : {
              resProxy : /\@{3}RESPREFIX\@{3}/g,
              prefix : /\@{3}PREFIX\@{3}/g
            },
            target : {
              resProxy : resProxy,
              prefix : prefix
            }
        }))
      .pipe(gulp.dest(paths.build+'/html'))
      .pipe(reload({stream:true}));
});

/* 壓縮圖片 */
gulp.task('images', function () {
  return gulp.src(paths.img + "**/*")
          .pipe(imagemin())
          .pipe(gulp.dest(paths.build + "/images"));
});

/* 解決js模塊化及依賴問題 */
gulp.task('browserify', function () {
  var b = browserify({
        entries: ["./src/js/index.js"],
        debug: true
    });
    return b.bundle()
        .pipe(source("index.js"))
        .pipe(buffer())
        .pipe(sourcemaps.init({loadMaps: true}))
        .pipe(gulp.dest("./build/js"))
        .pipe(uglify())
        .pipe(sourcemaps.write("."))
        .pipe(replace({
                original : {
                  resProxy : /\@{3}RESPREFIX\@{3}/g,
                  prefix : /\@{3}PREFIX\@{3}/g
                },
                target : {
                  resProxy : resProxy,
                  prefix : prefix
                }
            }))
        .pipe(gulp.dest("./build/js"))
        .pipe(reload({stream:true}));
});

/* Css樣式文件監控任務 */
gulp.task('watchCss', function () {
  gulp.watch('./src/css/block_css/*.css', function (done) {
    condition = false;
    runSequence(['handleCss'], ['revHtml'], ['bro'], done);
  });
});

/* 默認啓動任務 */
gulp.task('default', ['runLess', 'html', 'images', 'browserify'], function () {
  gulp.watch(['**/*.less', '**/*.css'], ['runLess']);
  gulp.watch('**/*.html', ['html']);
  gulp.watch('**/*.js', ['browserify']);
});

/* 本地服務,自動刷新 */
gulp.task('server', function (done) {
    condition = false;
    runSequence(['browser'], ['handleCss'], ['handleJs'], ['revHtml'], ['revManageHtml'], ['bro'], done);
    gulp.watch('./src/css/block_css/*.css', function () {     //監控全部CSS文件
      runSequence(['handleCss'], ['revHtml'], ['revManageHtml'], ['bro'], done);
    });
    gulp.watch(['./src/angular/**/*.js', './src/angular/*.js'], function () {     //監控全部JS文件
      runSequence(['handleJs'], ['revHtml'], ['revManageHtml'], ['bro'], done);
    });
    gulp.watch([
      './src/*.html',
      './src/views/*.html',
      './src/views/**/*.html',
      './src/manage/*.html'], ['bro']);
});
相關文章
相關標籤/搜索