老舊的項目,日復一日的縫縫補補,沒有大的動盪,其實一直維持着原有的樣子也是能夠的...html
不過就這樣子的話也太沒意思了。前端
眼看着當前各類炫酷的框架操做,好生羨慕,舊項目積重難返,但內心卻早已種草《大公司裏怎樣開發和部署前端代碼》,想動手實現一番。文章裏的思路,在評論裏有人指出 Ruby on Rails 其實早就有這樣的實現了,即 Asset Pipeline,這兩均可以拜讀一番。node
趁着手上工做告一段落,暫時有空閒時間,跟後端小夥伴商量着怎麼處理這個緩存問題,因每次發版都會引起緩存問題,運營人員、用戶每次都要強刷,確實蛋疼。webpack
期間找了現有的方案,找來找去仍是百度出的 fis 知足一切需求,可是項目已經停滯了許久,便做罷。後面想着與其這樣動找西找的,不如本身動手拼湊個!!!git
經過上述暴露的問題,就着手一個一個拆分解決了。github
針對第一個問題,後端經過修改原有的加載方式,在加載的時候都去讀取由前端這邊生成的資源表,匹配資源,在表上的就替換上去,不在的就回退到備用(原有)的資源那邊。web
能夠看到關鍵詞:資源表、匹配、替換,確定不多是人肉去搞這個了,這樣神都救不了你。項目自己使用的 gulp
去作一些重複的操做的(壓縮、混淆、複製搬運這些),那就繼續在這上面搗鼓好了(webpack只是淺嘗輒止)。chrome
這個能夠經過 gulp-rev
和 gulp-rev-collector
插件來生成、替換內容,因學藝不精因此裏面有些是人肉寫的,未經過插件去實現。npm
生成文件指紋:gulp
藉助於 node
的 crypto
模塊,咱們能夠經過如下方式簡單的瞭解下指紋的生成(代碼來自 npm 包插件:rev-hash):
'use strict'; const crypto = require('crypto'); module.exports = input => { if (typeof input !== 'string' && !Buffer.isBuffer(input)) { throw new TypeError('Expected a Buffer or string'); } return crypto.createHash('md5').update(input).digest('hex').slice(0, 10); };
喏,這就是指紋生成啦。
指紋的生成簡單,可是替換上就比較麻煩了,由於路徑都是寫在後端模板內的,你前端也操做不了。因此這裏就須要生成資源表給到後端,後端經過讀取該資源表去匹配替換了。
後端處理好該問題,那麼上述的第2、第3、第四的問題也就解決了。後端發版時,拉取新的資源表便可,無需再去手動修改版本號,前端能夠更好的控制資源了。
由於項目中用到了 requirejs
,因此其配置文件也須要替換,沒有用到 gulp-rev-collector
,人肉簡單的使用了 replace
方法去替換資源表上的內容。
期間就遇到這樣的問題:每次更新資源時,刪除整個版本目錄,生成新的版本資源仍是保留原有資源,生成新的資源。
整個刪除(覆蓋式發佈):在資源發版後會有短暫的資源找不到的問題(有可能來不及刷新資源表),可是好處是不會有冗餘的文件存在。
保留舊文件,生成新文件(非覆蓋式發佈):隨着時間的推移,版本化的文件內容會日積月累,變得越發龐大,單是咱們這邊設想的起碼保留3+1份(上上次、上次、當前 + 回退用的未版本化的文件)。
固然,爲了不前者帶來的短暫問題,咱們選擇了後者,經過定時任務去清理過時文件(git 從新拉取到本地的話,全部文件的建立時間、修改時間、訪問時間都是同樣的,因此不能在本地對其進行操做)。
上面有提到過該問題,咱們採用的重命名文件的形式,爲何不使用附帶查詢字符串的形式呢?
其實前面的知乎大神已解釋了該緣由,《高性能網站建設指南》的做者也在書中提到了,這是他博文上的觀點:Revving Filenames: don’t use querystring,博文是10年前的了...10年前的...10年前...10年...10...1...。
經過查看 chrome
的 network
面板,能夠看到 size
欄顯示了第二次訪問的資源,有些顯示的是 from memory cache,有些則是 from disk cache,status
欄顯示的狀態碼都是 200
而在 firefox
下顯示的倒是 304
已緩存的狀態,這又是爲何呢?