老樹新花:舊有項目的簡易前端資源緩存處理

老舊的項目,日復一日的縫縫補補,沒有大的動盪,其實一直維持着原有的樣子也是能夠的...html

不過就這樣子的話也太沒意思了。前端

眼看着當前各類炫酷的框架操做,好生羨慕,舊項目積重難返,但內心卻早已種草《大公司裏怎樣開發和部署前端代碼》,想動手實現一番。文章裏的思路,在評論裏有人指出 Ruby on Rails 其實早就有這樣的實現了,即 Asset Pipeline,這兩均可以拜讀一番。node

趁着手上工做告一段落,暫時有空閒時間,跟後端小夥伴商量着怎麼處理這個緩存問題,因每次發版都會引起緩存問題,運營人員、用戶每次都要強刷,確實蛋疼。webpack

期間找了現有的方案,找來找去仍是百度出的 fis 知足一切需求,可是項目已經停滯了許久,便做罷。後面想着與其這樣動找西找的,不如本身動手拼湊個!!!git

現有問題

  1. 項目是舊有的合做方式:前端出稿、腳本交互,PHP 後端套版,資源引用都是寫死耦合在 PHP 模板內,不可能抽離(前面諮詢事後端的小夥伴,由於框架自己有提供緩存功能,可是由於本身定義了一套資源加載的方法因此自帶的緩存管理就用不上了)。
  2. 前端有本身的靜態資源發佈權限,只是修改樣式、腳本、圖片時能夠本身操做發佈。可是問題是資源的版本管理是經過路徑後附帶查詢字符串的形式去實現的,且由後端手動控制,這邊修改一次須要後端手動修改版本號兩邊一塊兒發版。
  3. 因這邊的全部緩存管理都是經過附帶同一個查詢字符串實現,當修改一個時,其它的文件的版本號亦一同改變,全部緩存失效,須要從新來過,緩存形同虛設。
  4. 圖片文件更新後,得不到有效更新,使用的仍是舊內容。
  5. 修改版本查詢字符串還不必定生效(後面會說明爲何會這樣)

經過上述暴露的問題,就着手一個一個拆分解決了。github

針對第一個問題,後端經過修改原有的加載方式,在加載的時候都去讀取由前端這邊生成的資源表匹配資源,在表上的就替換上去,不在的就回退到備用(原有)的資源那邊。web

能夠看到關鍵詞:資源表、匹配、替換,確定不多是人肉去搞這個了,這樣神都救不了你。項目自己使用的 gulp 去作一些重複的操做的(壓縮、混淆、複製搬運這些),那就繼續在這上面搗鼓好了(webpack只是淺嘗輒止)。chrome

資源表的生成

這個能夠經過 gulp-revgulp-rev-collector 插件來生成、替換內容,因學藝不精因此裏面有些是人肉寫的,未經過插件去實現。npm

生成文件指紋:gulp

  • 建立時間(有隱患:本地 git 刪除,從新拉取,其建立時間、修改時間、訪問時間都是同樣的)
  • 文件內容

藉助於 nodecrypto 模塊,咱們能夠經過如下方式簡單的瞭解下指紋的生成(代碼來自 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...。

非覆蓋式發佈的資源冗餘處理

200 vs 304

經過查看 chromenetwork 面板,能夠看到 size欄顯示了第二次訪問的資源,有些顯示的是 from memory cache,有些則是 from disk cache,status欄顯示的狀態碼都是 200

而在 firefox 下顯示的倒是 304 已緩存的狀態,這又是爲何呢?

相關文章
相關標籤/搜索