首先要明確為什么要進(jìn)行前端靜態(tài)資源的版本管理糠悯,其主要目的是為了解決瀏覽器緩存問(wèn)題你稚,很多人會(huì)說(shuō)瀏覽器緩存不是服務(wù)端通過(guò)設(shè)置Etag
和過(guò)期時(shí)間
之類(lèi)的就可以嗎扭粱?為什么前端還要管理緩存扶歪?還有人可能會(huì)說(shuō)狞谱,緩存這么麻煩掸刊,那么可以不緩存免糕?
帶著上面的疑問(wèn),所以我們要了解瀏覽器緩存。
瀏覽器緩存基本認(rèn)識(shí)
瀏覽器緩存能有效減輕資源服務(wù)器的請(qǐng)求量石窑,提高網(wǎng)頁(yè)或應(yīng)用程序的資源訪問(wèn)速度牌芋,所以一個(gè)WEB應(yīng)用,緩存是必不可以少的優(yōu)化利器尼斧。
緩存分為:
- 強(qiáng)緩存
- 協(xié)商緩存
強(qiáng)緩存
通過(guò)服務(wù)器返回response header中的Expires或者Cache-Control的時(shí)間來(lái)決定是否從本地讀取緩存資源姜贡。
字段 | http版本 | 說(shuō)明 |
---|---|---|
Expires | http1.0 | 返回GMT的絕對(duì)時(shí)間 |
Cache-Control | http1.1 | 以秒為單位的過(guò)期時(shí)間 |
協(xié)商緩存
當(dāng)瀏覽器對(duì)某個(gè)資源的請(qǐng)求沒(méi)有命中強(qiáng)緩存,就會(huì)發(fā)一個(gè)請(qǐng)求到服務(wù)器棺棵,驗(yàn)證協(xié)商緩存是否命中楼咳,如果協(xié)商緩存命中,請(qǐng)求響應(yīng)返回的http狀態(tài)為304烛恤。當(dāng)瀏覽器收到304響應(yīng)時(shí)母怜,就會(huì)直接從本地緩存讀取資源。
協(xié)商緩存是利用的是【Last-Modified缚柏,If-Modified-Since】和【ETag苹熏、If-None-Match】這兩對(duì)Header來(lái)管理的。
強(qiáng)緩存和協(xié)商緩存的共同點(diǎn)
強(qiáng)緩存與協(xié)商緩存的共同點(diǎn)是:如果命中币喧,都是從客戶(hù)端緩存中加載資源轨域,而不是從服務(wù)器加載資源數(shù)據(jù);區(qū)別是:強(qiáng)緩存不發(fā)請(qǐng)求到服務(wù)器杀餐,協(xié)商緩存會(huì)發(fā)請(qǐng)求到服務(wù)器干发。
前端刷新緩存
根據(jù)前面緩存的基本知識(shí),當(dāng)資源被強(qiáng)緩存時(shí)史翘,而資源版本已在服務(wù)器更新枉长,這時(shí)我們就需要刷新緩存。當(dāng)文件重命名或文件URL添加參數(shù)琼讽,都可以刷新緩存必峰。
一般通過(guò)兩種方式來(lái)刷新:
- 資源重新命名,如:
index.js
更新為index_a083082f.js
- 資源鏈接添加變化的參數(shù)钻蹬,如:
index.js
更新為index.js?hash=a083082f
資源重新命名
從可用性角度說(shuō)吼蚁,大型web應(yīng)用中,資源重新命名是最優(yōu)的選擇问欠,因?yàn)樾碌馁Y源文件不會(huì)覆蓋正在運(yùn)行的資源文件肝匆,比如關(guān)鍵邏輯的JS腳本文件。而且CDN回源需要一定的時(shí)間才能全網(wǎng)生效溅潜,等資源文件生效后再進(jìn)行HTML文件的發(fā)布。HTML文件強(qiáng)制不緩存薪伏,就能很好的達(dá)到WEB應(yīng)用版本更新的目的滚澜。
資源重新命名,也同時(shí)會(huì)造成大量無(wú)效舊版文件存在于CDN或版本管理服務(wù)器(SVN,GIT)嫁怀。
資源鏈接添加變化的參數(shù)
一般添加資源更新日期或文件內(nèi)容的hash值设捐。
但不管哪種方式借浊,手動(dòng)修改文件版本號(hào),只適用于非常小型的應(yīng)用萝招。我們需要的是一個(gè)自動(dòng)化的前端工具來(lái)做這件事蚂斤。
于是筆者就造了以下兩個(gè)輪子:
- gulp-hash-list ,主要作用是讀取資源槐沼,計(jì)算hash值曙蒸,按指定的格式生成一個(gè)清單文件。
-
gulp-asset-revision
讀取資源列表的清單文件岗钩,替換HTML中的js,css等資源引用地址纽窟。
gulp-hash-list和gulp-asset-revision的使用
var gulp = require('gulp');
var hash = require('gulp-hash-list');
var revision = require('gulp-asset-revision');
gulp.task('hash', function() {
return gulp.src(['./src/**/*.js','./src/**/*.css'])
.pipe(hash({
"template": "{name}{ext}?hash={hash}"
}))
.pipe(gulp.dest('./dist'))
.pipe(hash.manifest('assets.json'))
.pipe(gulp.dest('./manifest'));
});
gulp.task('revision', ['hash'], function() {
return gulp.src(['./pages/*.html'])
.pipe(revision({
hasSuffix: false,
manifest: './manifest/assets.json'
}))
.pipe(gulp.dest('./pages/'));
});
為什么要選用gulp-hash-list和gulp-asset-revision
其實(shí)Gulp生態(tài)已經(jīng)有gulp-rev
+ gulp-rev-collector
這種優(yōu)秀的方案,但是它只支持生成新的文件名兼吓,不支持添加參數(shù)的形式臂港。
而gulp-hash-list
和gulp-asset-revision
不僅可以支持生成新文件,同時(shí)支持添加參數(shù)的形式刷新資源版本號(hào)视搏,以更新緩存审孽。