詳解前端自動(dòng)化工具gulp自動(dòng)添加版本號(hào)
之前,我介紹了學(xué)習(xí)安裝并配置前端自動(dòng)化工具Gulp,覺得gulp確實(shí)比grunt的配置簡(jiǎn)單很多,于是我決定再深入學(xué)習(xí)一下gulp,就去網(wǎng)上查了資料,發(fā)現(xiàn)gulp還可以自動(dòng)添加版本號(hào),這個(gè)功能就為我平時(shí)在更新css或js時(shí)老是在客戶端存在緩存導(dǎo)致更新后的效果無法實(shí)時(shí)展現(xiàn)的苦惱。所以就趕緊去試了一下,果真可以,很高興啊,真是為項(xiàng)目開發(fā),為效果的快速展現(xiàn)提供了很多的便利。
實(shí)現(xiàn)原理:
1、修改js和css文件;
2、通過對(duì)js,css文件內(nèi)容進(jìn)行hash運(yùn)算,生成一個(gè)文件的唯一hash字符串(如果文件修改則hash號(hào)會(huì)發(fā)生變化);
3、替換html中的js,css文件名,生成一個(gè)帶版本號(hào)的文件名。
現(xiàn)在網(wǎng)上的方案都是生成一個(gè)新的dist目錄,里面包含了要發(fā)布的html、js、css等文件。但是在實(shí)際的公司的項(xiàng)目中,會(huì)有情況不能生成新的HTML進(jìn)行發(fā)布,需要在原來的HTML文件上進(jìn)行js 、css版本的替換. 這里分享下我在實(shí)際項(xiàng)目中通過改動(dòng)插件然后在原目錄結(jié)構(gòu)下進(jìn)行版本的控制方案。(在這里,我有點(diǎn)不太明白原作者的意思,因?yàn)槟慵热恍薷牧薺s或css,那么html中引入這些文件的版本號(hào)必然會(huì)發(fā)生變化,也就是html也跟著變化了,如果你不對(duì)新的html進(jìn)行發(fā)布,那線上的html中的版本號(hào)還是老的版本號(hào),就沒有起到更新緩存的作用,那我們辛辛苦苦的配置gulp來添加這個(gè)版本號(hào)干嘛?)
原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")
實(shí)現(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ù)針對(duì)的文件 .pipe(assetRev()) //該任務(wù)調(diào)用的模塊 .pipe(gulp.dest('src/css')); //編譯后的路徑 }); //CSS生成文件hash編碼并生成 rev-manifest.json文件名對(duì)照映射 gulp.task('revCss', function(){ return gulp.src(cssSrc) .pipe(rev()) .pipe(rev.manifest()) .pipe(gulp.dest('rev/css')); }); //js生成文件hash編碼并生成 rev-manifest.json文件名對(duì)照映射 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也可以實(shí)現(xiàn)以上所有任務(wù)的執(zhí)行,只是gulp.run是最大限度的并行執(zhí)行這些任務(wù),而在添加版本號(hào)時(shí)需要串行執(zhí)行(順序執(zhí)行)這些任務(wù),故使用了runSequence. ['assetRev'], ['revCss'], ['revJs'], ['revHtml'], done); });
執(zhí)行g(shù)ulp命令后的效果
//rev目錄下生成了manifest.json對(duì)應(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é)果會(huì)如下:
<link rel="stylesheet" href="../css/default.css?v=33379df310?v=803a7fe4ae"> <script src="../js/app.js?v=3a0d844594?v=3a0d844594"></script>
有沒有發(fā)現(xiàn),會(huì)在版本號(hào)后面再添加一個(gè)版本號(hào),因?yàn)間ulp只替換了原來文件名,這樣又不符合預(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>
以下是本人自己寫的一個(gè)既可以編譯less,又可以壓縮、重命名css和js,同時(shí)可以壓縮html并自動(dòng)添加版本號(hào)的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 定義一個(gè)less任務(wù)(自定義任務(wù)名稱) gulp.task('less', function(){ return gulp.src(lessSrc) //該任務(wù)針對(duì)的文件 .pipe(less()) //該任務(wù)調(diào)用的模塊 .pipe(gulp.dest('css'));//編譯后的路徑 }); //為css中引入的圖片/字體等添加hash編碼 gulp.task('assetRev', function(){ return gulp.src(cssSrc) //該任務(wù)針對(duì)的文件 .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文件名對(duì)照映射 gulp.task('revCss', function(){ return gulp.src(cssMinSrc) .pipe(rev()) //文件名加MD5后綴 .pipe(rev.manifest()) //必須有這個(gè)方法 生成一個(gè)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文件名對(duì)照映射 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è)置這個(gè)屬性后,就會(huì)變成 <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()) //必須有這個(gè)方法 .pipe(gulp.dest('dist/images')); }); gulp.task('default', function (done) { //condition = false; runSequence( //此處不能用gulp.run這個(gè)最大限度并行(異步)執(zhí)行的方法,要用到runSequence這個(gè)串行方法(順序執(zhí)行)才可以在運(yùn)行g(shù)ulp后順序執(zhí)行這些任務(wù)并在html中加入版本號(hào) 'less', 'assetRev', 'cssMin', 'revCss', 'uglify', 'revJs', 'imageMin', 'revImage', 'htmlMin', 'revHtml', done); });
目前,不知為何必須要運(yùn)行兩次gulp才可以給html中引入的圖片添加版本號(hào),所以還在摸索中,也請(qǐng)大神給指點(diǎn)指點(diǎn),謝謝!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
微信小程序如何實(shí)現(xiàn)radio單選框單擊打勾和取消
這篇文章主要介紹了微信小程序如何實(shí)現(xiàn)radio單選框單擊打勾和取消,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01JavaScript 函數(shù)惰性載入的實(shí)現(xiàn)及其優(yōu)點(diǎn)介紹
惰性載入表示函數(shù)執(zhí)行的分支只會(huì)在函數(shù)第一次掉用的時(shí)候執(zhí)行,在第一次調(diào)用過程中,該函數(shù)會(huì)被覆蓋為另一個(gè)按照合適方式執(zhí)行的函數(shù),這樣任何對(duì)原函數(shù)的調(diào)用就不用再經(jīng)過執(zhí)行的分支了2013-08-08JavaScript定時(shí)器設(shè)置、使用與倒計(jì)時(shí)案例詳解
這篇文章主要介紹了JavaScript定時(shí)器設(shè)置、使用與倒計(jì)時(shí)案例,詳細(xì)分析了javascript定時(shí)器的設(shè)置、取消、循環(huán)調(diào)用并附帶一個(gè)倒計(jì)時(shí)功能應(yīng)用案例,需要的朋友可以參考下2019-07-07用原生js統(tǒng)計(jì)文本行數(shù)的簡(jiǎn)單示例
這篇文章我們來看看如何利用原生的JavaScript實(shí)現(xiàn)統(tǒng)計(jì)文本的行數(shù),代碼實(shí)現(xiàn)起來很簡(jiǎn)單,有需要的可以參考借鑒。2016-08-08給超鏈接添加特效鼠標(biāo)移動(dòng)展示提示信息且隨鼠標(biāo)移動(dòng)
需要實(shí)現(xiàn)這樣的效果,就是給超鏈接添加特效當(dāng)鼠標(biāo)移動(dòng)到上展示提示信息且提示信息跟隨鼠標(biāo)移動(dòng),經(jīng)測(cè)試還不錯(cuò),感興趣的朋友可以參考下2013-10-10