gulp管理靜態資源緩存
前端項目在版本叠代的時候,難免會遇到靜態緩存的問題,明明開發的是ok的,但是一部署到服務器上,發現頁面變得亂七八糟,這是由於靜態緩存引起的。
從上面這張圖片可以看出,瀏覽器加載css,js等資源時,size一欄是from cache,也就是直接使用了本地的資源,而沒有向服務器請求。這樣做的好處是提升頁面渲染速度,壞處是當服務器的對應的文件發生變化時,瀏覽器卻還是使用緩存,造成布局混亂的問題。
解決辦法
一個比較原始的辦法是在修改了文件之後,手動改變文件名稱,然後再在html手動更新資源的path名稱。打個比方,你有一天更新了a.css的樣式,然後加個日期後綴,把它重命名為a-1221.css
<link href="./css/a-1221.css" rel="stylesheet"/>
這時,但瀏覽器發現需要加載這個樣式時,發現自己只有a.css,沒有a-1221.css,就會向服務器發起請求了。不過,很明顯,這種活大家是都不願意幹的,尤其是css文件一多的時候,絕對懵逼,所幸我們可以讓gulp來幫我們完成這些乏味的工作。
gulp-rev 和 gulp-rev-collector
這是兩個gulp的插件,gulp-rev可以根據靜態資源的得出文件的hash值,當文件內容發生改變時,這個hash值也會發生變化。並生成一個json文件,大概長這個樣子:
{
"base/index.css": "base/index-c52f09f203.css"
}
文件的後綴變成了這個文件的hash值。gulpfile.js中的代碼如下:
var rev = require(‘gulp-rev‘);
var gulp = require(‘gulp‘);
gulp.task(‘revCss‘, function(){
return gulp.src(cssUrl)//你存放css的目錄
.pipe(rev())
.pipe(rev.manifest())
.pipe(gulp.dest(‘rev/css‘));//在rev/css目錄下生成json文件
});
這個插件只解決了問題的一部分,也就是,把文件變動和hash值關聯了起來,另一部分改變html的請求路徑還要靠第二個插件gulp-rev-collector來完成。這個插件完成的事情也很簡單,就是把html中的資源路徑,通過正則匹配,替換成更新後的路徑。代碼如下:
var gulp = require(‘gulp‘);
var revCollector = require(‘gulp-rev-collector‘);
gulp.task(‘revHtml‘, function () {
return gulp.src([‘rev/**/*.json‘, ‘views/*.html‘])
.pipe(revCollector())
.pipe(gulp.dest(‘views/inc/‘));
});
所以這兩個插件就解決問題了嗎?可惜並不是這樣。因為你的css文件名並沒有更改,還是原來的a.css,所以還需要一個插件幫我們解決重命名的問題。比如用來重命名文件的gulp-rename。
var rename = require("gulp-rename");
var json = require(‘./rev-manifest.json‘);//rev生成的文件
gulp.task(‘rename‘,function(){
var json = require(‘./rev/css/rev-manifest.json‘);
var Path = require(‘path‘);
gulp.src("static/css/*.css")
.pipe(rename(function (path) {
path.basename = json[path.basename + ‘.css‘].replace(‘.css‘, ‘‘);//改掉css文件名為含有hash值的文件名
}))
.pipe(gulp.dest("./dist"));
})
查詢參數管理緩存
查詢參數這種方法適用於前後端不分離的項目,因為這時再去重命名靜態文件就會顯得很麻煩。所以出現了這種做法,就是在靜態資源發生變化時,文件名不改變,但是html中請求路徑的查詢參數會發生變化,像下面這樣:
<link rel="stylesheet" href="/css/style.css?v=2h3h2ar">
這個查詢參數v對於後臺來說,沒有什麽意義,你完全可以改成a,b,c。但是當查詢參數的hash值發生變化時,卻會讓瀏覽器去向服務器發起請求,從而更新緩存。如果你想用這種方式,可以使用gulp-rev-query(github)插件和gulp-rev-collector-query,將文件名轉換成查詢字符串。(插件的一個bug是對於.min.css會解析錯誤)
{
"base/index.css": "base/index.css?v=1ead88a42c"
}
下面是我參考作者的寫的一個,解決了min.js的問題,其實就是改了正則:
var through = require(‘through2‘);
module.exports = function(ver) {
var ver = ver || ‘v‘
// convert a-xxxxxxxx.css to a.css?ver=xxxxxxxx
function hashToQuery(file) {
var content = new String(file._contents);
content = content.replace(/(.+)\-(.{7,10})(\..+)"/g, function(match, p1,p2,p3,offset,string){
return `${p1}${p3}?${ver}=${p2}"`
});
file._contents = new Buffer(content);
file.ver = ver;
return file;
}
return through.obj(function(file, encoding, callback) {
callback(null, hashToQuery(file));
});
};
最後,祝大家聖誕快樂!
gulp管理靜態資源緩存