當咱們將遊戲構建發佈到web平臺時,勾選Md5 Cache選項能夠開啓MD5 Pipe,它的做用是給構建後的資源加上md5後綴,避免瀏覽器的緩存致使部分資源不是最新,由於使用了md5後綴後,當資源內容發生變化時,資源的名字就不同了,緩存就會失效。web
好比6e056173-d285-473c-b206-40a7fff5386e.json,在開啓了MD5 Cache選項以後再構建會生成6e056173-d285-473c-b206-40a7fff5386e.a548e.json,在文件後綴.json前加上了一個簡化的md5——a548e。json
勾選了Md5 Cache選項後進行構建,生成的web-mobile/src/settings.xxx.js文件中會設置一個全局變量_CCSettings,該變量中有一個md5AssetsMap字段記錄全部資源文件的簡化md5。瀏覽器
md5AssetsMap: { "08/08ddbd1c9.json": "ade93", "6e/6e056173-d285-473c-b206-40a7fff5386e.json": "a548e", "assets/6e/6e056173-d285-473c-b206-40a7fff5386e.png": "68270" }
在Creator生成的main.xxx.js中會獲取_CCSettings變量進行處理,一個關鍵的地方就是cc.AssetLibrary.init,將settings.md5AssetsMap傳入AssetLibrary。緩存
cc.AssetLibrary.init({ libraryPath: 'res/import', rawAssetsBase: 'res/raw-', rawAssets: settings.rawAssets, packedAssets: settings.packedAssets, md5AssetsMap: settings.md5AssetsMap });
在cc.AssetLibrary.init中,根據md5AssetsMap變量決定是否建立MD5Pipe,將md5Pipe插入到cc.loader.assetLoader以後。ide
var md5AssetsMap = options.md5AssetsMap; if (md5AssetsMap) { var md5Pipe = new MD5Pipe(md5AssetsMap, _libraryBase, _rawAssetsBase); cc.loader.insertPipeAfter(cc.loader.assetLoader, md5Pipe); cc.loader.md5Pipe = md5Pipe; }
在一些核心模塊中,咱們能夠看到直接使用url時,都會檢測是否存在cc.loader.md5Pipe,有則調用其transformURL對url進行處理,好比CCVideoPlayer.js,這些處理屬於不走Pipeline的路徑處理,屬於這些組件的內部邏輯。this
_updateVideoSource: function () { var sgNode = this._sgNode; let url = ''; if (this.resourceType === ResourceType.REMOTE) { url = this.remoteURL; } else if (this._clip) { url = this._clip.nativeUrl || ''; } if (url && cc.loader.md5Pipe) { url = cc.loader.md5Pipe.transformURL(url); } sgNode.setURL(url); },
Md5 Pipe的實現很是簡單(位於load-pipeline下的md5-pipe.js),它只對res/import或res/raw-開頭的url進行處理,根據md5AssetsMap對應的精簡md5值,從新組裝url。url
MD5Pipe.prototype.transformURL = function (url, hashPatchInFolder) { var index = url.indexOf('?'); var key = url; if (index !== -1) { key = url.substr(0, index); } // 若是是以libraryBase開頭'res/import',去掉這個前綴 if (key.startsWith(this.libraryBase)) { key = key.slice(this.libraryBase.length); // 若是是以rawAssetsBase開頭'res/raw-',也去掉這個前綴 } else if (key.startsWith(this.rawAssetsBase)) { key = key.slice(this.rawAssetsBase.length); } else { // 其餘狀況不處理,好比是一個完整的http連接 return url; } // 取出該資源對應的精簡md5 let hashValue = this.md5AssetsMap[key]; if (hashValue) { // 若是hashPatchInFolder爲true則將這個md5組裝到目錄下 // JSB下的Spine、Label都有使用hashPatchInFolder if (hashPatchInFolder) { var dirname = cc.path.dirname(url); var basename = cc.path.basename(url); url = `${dirname}.${hashValue}/${basename}`; } else { // 正常狀況是將精簡md5插入到文件擴展名以前 var matched = false; url = url.replace(ExtnameRegex, (function(match, p1) { matched = true; return "." + hashValue + p1; })); if (!matched) { url = url + "." + hashValue } } } return url; };