詳解前端自動化工具gulp自動添加版本號
之前,我介紹了學(xué)習(xí)安裝并配置前端自動化工具Gulp,覺得gulp確實比grunt的配置簡單很多,于是我決定再深入學(xué)習(xí)一下gulp,就去網(wǎng)上查了資料,發(fā)現(xiàn)gulp還可以自動添加版本號,這個功能就為我平時在更新css或js時老是在客戶端存在緩存導(dǎo)致更新后的效果無法實時展現(xiàn)的苦惱。所以就趕緊去試了一下,果真可以,很高興啊,真是為項目開發(fā),為效果的快速展現(xiàn)提供了很多的便利。
實現(xiàn)原理:
1、修改js和css文件;
2、通過對js,css文件內(nèi)容進(jìn)行hash運算,生成一個文件的唯一hash字符串(如果文件修改則hash號會發(fā)生變化);
3、替換html中的js,css文件名,生成一個帶版本號的文件名。
現(xiàn)在網(wǎng)上的方案都是生成一個新的dist目錄,里面包含了要發(fā)布的html、js、css等文件。但是在實際的公司的項目中,會有情況不能生成新的HTML進(jìn)行發(fā)布,需要在原來的HTML文件上進(jìn)行js 、css版本的替換. 這里分享下我在實際項目中通過改動插件然后在原目錄結(jié)構(gòu)下進(jìn)行版本的控制方案。(在這里,我有點不太明白原作者的意思,因為你既然修改了js或css,那么html中引入這些文件的版本號必然會發(fā)生變化,也就是html也跟著變化了,如果你不對新的html進(jìn)行發(fā)布,那線上的html中的版本號還是老的版本號,就沒有起到更新緩存的作用,那我們辛辛苦苦的配置gulp來添加這個版本號干嘛?)
原h(huán)tml文件代碼
<link rel="stylesheet" href="../css/default.css"> <script src="../js/app.js"></script>
預(yù)期效果:在原目錄結(jié)構(gòu)下html文件代碼
<link rel="stylesheet" href="../css/default.css?v=5a636d79c4"> <script src="../js/app.js?v=3a0d844594"></script> background:url("../images/none.png?v=8f204d4")
實現(xiàn)方法:
1、安裝gulp和gulp插件
npm install --save-dev gulp npm install --save-dev gulp-rev npm install --save-dev gulp-rev-collector npm install --save-dev gulp-asset-rev npm install --save-dev run-sequence
2、編寫gulpfile.js
//引入gulp和gulp插件 var gulp = require('gulp'), assetRev = require('gulp-asset-rev'), runSequence = require('run-sequence'), rev = require('gulp-rev'), revCollector = require('gulp-rev-collector'); //定義css、js源文件路徑 var cssSrc = 'css/*.css', jsSrc = 'js/*.js'; //為css中引入的圖片/字體等添加hash編碼 gulp.task('assetRev', function(){ return gulp.src(cssSrc) //該任務(wù)針對的文件 .pipe(assetRev()) //該任務(wù)調(diào)用的模塊 .pipe(gulp.dest('src/css')); //編譯后的路徑 }); //CSS生成文件hash編碼并生成 rev-manifest.json文件名對照映射 gulp.task('revCss', function(){ return gulp.src(cssSrc) .pipe(rev()) .pipe(rev.manifest()) .pipe(gulp.dest('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', 'View/*.html']) .pipe(revCollector()) .pipe(gulp.dest('View')); }); //開發(fā)構(gòu)建 gulp.task('default', function (done) { condition = false; runSequence( //需要說明的是,用gulp.run也可以實現(xiàn)以上所有任務(wù)的執(zhí)行,只是gulp.run是最大限度的并行執(zhí)行這些任務(wù),而在添加版本號時需要串行執(zhí)行(順序執(zhí)行)這些任務(wù),故使用了runSequence. ['assetRev'], ['revCss'], ['revJs'], ['revHtml'], done); });
執(zhí)行g(shù)ulp命令后的效果
//rev目錄下生成了manifest.json對應(yīng)文件 { "default.css": "default-803a7fe4ae.css" } <link rel="stylesheet" href="../css/default-803a7fe4ae.css"> <script src="../js/app-3a0d844594.js"></script>
很顯然這不是我們需要的效果
3、更改gulp-rev和gulp-rev-collector
打開node_modules\gulp-rev\index.js
第144行 manifest[originalFile] = revisionedFile;
更新為: manifest[originalFile] = originalFile + '?v=' + file.revHash;
打開nodemodules\gulp-rev\nodemodules\rev-path\index.js
10行 return filename + '-' + hash + ext;
更新為: return filename + ext;
打開node_modules\gulp-rev-collector\index.js
31行 if ( !_.isString(json[key]) || path.basename(json[key]).replace(new RegExp( opts.revSuffix ), '' ) !== path.basename(key) ) {
更新為: if ( !_.isString(json[key]) || path.basename(json[key]).split('?')[0] !== path.basename(key) ) {
打開node_modules\gulp-assets-rev\index.js
78行 var verStr = (options.verConnecter || "-") + md5;
更新為:var verStr = (options.verConnecter || "") + md5;
80行 src = src.replace(verStr, '').replace(/(\.[^\.]+)$/, verStr + "$1");
更新為:src=src+"?v="+verStr;
再執(zhí)行g(shù)ulp命令,得到的結(jié)果如下(效果正確):
<link rel="stylesheet" href="../css/default.css?v=803a7fe4ae"> <script src="../js/app.js?v=3a0d844594"></script> background:url("../images/none.png?v=8f204d4")
但是假如我們更改了css和js后,再執(zhí)行g(shù)ulp命令,得到的結(jié)果會如下:
<link rel="stylesheet" href="../css/default.css?v=33379df310?v=803a7fe4ae"> <script src="../js/app.js?v=3a0d844594?v=3a0d844594"></script>
有沒有發(fā)現(xiàn),會在版本號后面再添加一個版本號,因為gulp只替換了原來文件名,這樣又不符合預(yù)期效果了,所以我們想到,還需要修改插件的替換正則表達(dá)式。
4、繼續(xù)更改gulp-rev-collector
打開node_modules\gulp-rev-collector\index.js
第107行 regexp: new RegExp( '([\/\\\\\'"])' + pattern, 'g' ),
更新為: regexp: new RegExp( '([\/\\\\\'"])' + pattern+'(\\?v=\\w{10})?', 'g' ),
現(xiàn)在你不管執(zhí)行多少遍gulp命令,得到的html效果都是
<link rel="stylesheet" href="../css/default.css?v=5a636d79c4"> <script src="../js/app.js?v=3a0d844594"></script>
以下是本人自己寫的一個既可以編譯less,又可以壓縮、重命名css和js,同時可以壓縮html并自動添加版本號的gulp.js配置文件,當(dāng)然也是參考了原作者的方法:
//引入gulp和gulp插件 var gulp = require('gulp'), less = require('gulp-less'), assetRev = require('gulp-asset-rev'), minifyCss = require('gulp-minify-css'), uglify = require('gulp-uglify'), htmlmin = require('gulp-htmlmin'), rename = require('gulp-rename'), imagemin = require('gulp-imagemin'), runSequence = require('run-sequence'), rev = require('gulp-rev'), revCollector = require('gulp-rev-collector'); //定義css、js源文件路徑 var cssSrc = 'css/*.css', cssMinSrc = 'dist/css/*.css', jsSrc = 'js/*.js', jsMinSrc = 'dist/js/*.js', lessSrc = 'less/*.less', imgMinSrc = 'dist/images/*.{png,jpg,gif,ico}', htmlSrc = '*.html'; //編譯less 定義一個less任務(wù)(自定義任務(wù)名稱) gulp.task('less', function(){ return gulp.src(lessSrc) //該任務(wù)針對的文件 .pipe(less()) //該任務(wù)調(diào)用的模塊 .pipe(gulp.dest('css'));//編譯后的路徑 }); //為css中引入的圖片/字體等添加hash編碼 gulp.task('assetRev', function(){ return gulp.src(cssSrc) //該任務(wù)針對的文件 .pipe(assetRev()) //該任務(wù)調(diào)用的模塊 .pipe(gulp.dest('src')); //編譯后的路徑 }); //壓縮css gulp.task('cssMin', function() { return gulp.src(cssSrc) //壓縮的文件 .pipe(rename({suffix: '.min'})) .pipe(minifyCss()) //執(zhí)行壓縮 .pipe(gulp.dest('dist/css')); //輸出文件夾 }); //CSS生成文件hash編碼并生成 rev-manifest.json文件名對照映射 gulp.task('revCss', function(){ return gulp.src(cssMinSrc) .pipe(rev()) //文件名加MD5后綴 .pipe(rev.manifest()) //必須有這個方法 生成一個rev-manifest.json .pipe(gulp.dest('dist/css')); //將rev-manifest.json 保存到 dist/css 目錄內(nèi) }); //壓縮js gulp.task('uglify',function(){ return gulp.src(jsSrc) .pipe(rename({suffix: '.min'})) .pipe(uglify()) .pipe(gulp.dest('dist/js')); }); //js生成文件hash編碼并生成 rev-manifest.json文件名對照映射 gulp.task('revJs', function(){ return gulp.src(jsMinSrc) .pipe(rev()) .pipe(rev.manifest()) .pipe(gulp.dest('dist/js')); }); //壓縮html gulp.task('htmlMin',function(){ var options = { collapseWhitespace:true, //從字面意思應(yīng)該可以看出來,清除空格,壓縮html,這一條比較重要,作用比較大,引起的改變壓縮量也特別大。 collapseBooleanAttributes:true, //省略布爾屬性的值,比如:<input checked="checked"/>,那么設(shè)置這個屬性后,就會變成 <input checked/>。 removeComments:true, //清除html中注釋的部分,我們應(yīng)該減少html頁面中的注釋。 removeEmptyAttributes:true, //清除所有的空屬性。 removeScriptTypeAttributes:true, //清除所有script標(biāo)簽中的type="text/javascript"屬性。 removeStyleLinkTypeAttributes:true, //清楚所有Link標(biāo)簽上的type屬性。 minifyJS:true, //壓縮html中的javascript代碼。 minifyCSS:true //壓縮html中的css代碼。 }; return gulp.src(htmlSrc) .pipe(htmlmin(options)) .pipe(gulp.dest('dist/html')); }); //Html替換css、js文件版本 gulp.task('revHtml', function () { return gulp.src(['dist/**/*.json', 'dist/html/*.html']) .pipe(revCollector()) .pipe(gulp.dest('dist/html')); }); //壓縮image gulp.task('imageMin', function () { gulp.src('images/*.{png,jpg,gif,ico}') .pipe(imagemin()) .pipe(gulp.dest('dist/images')); }); gulp.task('revImage', function(){ return gulp.src(imgMinSrc) .pipe(rev()) .pipe(rev.manifest()) //必須有這個方法 .pipe(gulp.dest('dist/images')); }); gulp.task('default', function (done) { //condition = false; runSequence( //此處不能用gulp.run這個最大限度并行(異步)執(zhí)行的方法,要用到runSequence這個串行方法(順序執(zhí)行)才可以在運行g(shù)ulp后順序執(zhí)行這些任務(wù)并在html中加入版本號 'less', 'assetRev', 'cssMin', 'revCss', 'uglify', 'revJs', 'imageMin', 'revImage', 'htmlMin', 'revHtml', done); });
目前,不知為何必須要運行兩次gulp才可以給html中引入的圖片添加版本號,所以還在摸索中,也請大神給指點指點,謝謝!
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
微信小程序如何實現(xiàn)radio單選框單擊打勾和取消
這篇文章主要介紹了微信小程序如何實現(xiàn)radio單選框單擊打勾和取消,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-01-01JavaScript 函數(shù)惰性載入的實現(xiàn)及其優(yōu)點介紹
惰性載入表示函數(shù)執(zhí)行的分支只會在函數(shù)第一次掉用的時候執(zhí)行,在第一次調(diào)用過程中,該函數(shù)會被覆蓋為另一個按照合適方式執(zhí)行的函數(shù),這樣任何對原函數(shù)的調(diào)用就不用再經(jīng)過執(zhí)行的分支了2013-08-08JavaScript定時器設(shè)置、使用與倒計時案例詳解
這篇文章主要介紹了JavaScript定時器設(shè)置、使用與倒計時案例,詳細(xì)分析了javascript定時器的設(shè)置、取消、循環(huán)調(diào)用并附帶一個倒計時功能應(yīng)用案例,需要的朋友可以參考下2019-07-07給超鏈接添加特效鼠標(biāo)移動展示提示信息且隨鼠標(biāo)移動
需要實現(xiàn)這樣的效果,就是給超鏈接添加特效當(dāng)鼠標(biāo)移動到上展示提示信息且提示信息跟隨鼠標(biāo)移動,經(jīng)測試還不錯,感興趣的朋友可以參考下2013-10-10