static-assets-loader
Version:
492 lines (395 loc) • 12.9 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var loadjs = _interopDefault(require('loadjs'));
/**
* 检测错误并抛出
* @param condition 是否抛出错误
* @param errorMsg
*/
var invariant = function invariant(condition, errorMsg) {
if (condition) {
throw new Error(errorMsg);
}
};
/**
* Get the website information of CDN
* '//cdn.bootcdn.net/ajax/libs/vue/3.2.33/vue.runtime.esm-browser.js' => 'cdn.bootcdn.net'
* @param url
* @returns
*/
var getPrefixUrl = function getPrefixUrl(url) {
if (!url) {
return '';
} // https:// => 8
// http:// => 7
// // => 2
var removePrefixIndex = url.indexOf('//') + 2; // get all strings between the current index and the first following / as path
return url.substring(removePrefixIndex, url.indexOf('/', removePrefixIndex));
};
/**
* Gets the object on the global variable
* vue => window.Vue
* @param umdName
* @returns
*/
var getWrapperDataFromGlobal = function getWrapperDataFromGlobal(umdName) {
if (!umdName || typeof umdName !== 'string') {
return null;
}
return globalThis[umdName];
};
/**
* 获取一个resolve 和reject在外面的promise对象
* @returns {Promise<unknown>}
*/
var createDeferredPromise = function createDeferredPromise() {
var resolve;
var reject;
var promise = new Promise(function (res, rej) {
resolve = res;
reject = rej;
});
return {
currentPromise: promise,
resolve: resolve,
reject: reject
};
};
var getStorage = function getStorage(strategy) {
if (strategy === 'sessionStorage') {
return sessionStorage;
}
if (strategy === 'localStorage') {
return localStorage;
}
return null;
};
/**
* Can't use URL
*/
var DEFAULT_MAX_AGE = 8 * (60 * 60);
var STORAGE_KEY = 'balUrlPrefix';
var DEFAULT_OPTIONS = {
storageKey: STORAGE_KEY,
strategy: 'memory',
maxAge: DEFAULT_MAX_AGE
};
var BadUrlPrefixCache = /*#__PURE__*/function () {
function BadUrlPrefixCache(config) {
var _this = this;
/**
* Cache problematic URLs
*/
this.urlPrefixCache = new Map();
this.getCacheFromStorage = function () {
var _getStorage;
var json = (_getStorage = getStorage(_this.config.strategy || '')) == null ? void 0 : _getStorage.getItem(_this.config.storageKey || STORAGE_KEY);
if (!json) {
return {};
}
try {
return JSON.parse(json);
} catch (error) {
return {};
}
};
this.add = function (url) {
var prefixUrl = getPrefixUrl(url);
if (_this.has(prefixUrl)) {
return;
}
var expiredTime = new Date().getTime() / 1000 + DEFAULT_MAX_AGE;
_this.urlPrefixCache.set(prefixUrl, expiredTime);
_this.setStorageForCache();
return _this;
};
this["delete"] = function (url) {
if (_this.isEmpty()) {
return;
}
_this.urlPrefixCache["delete"](getPrefixUrl(url));
_this.setStorageForCache();
return _this;
};
this.isOverTime = function (prefixUrl) {
var expiredTime = _this.urlPrefixCache.get(prefixUrl) || 0; // 没有数据项 一定超时
if (!expiredTime) {
return true;
} // 获取系统当前时间戳
var currentTime = new Date().getTime() / 1000; // 如果过去的秒数大于当前的超时时间,也返回null让其去服务端取数据
if (currentTime > expiredTime) {
// 此代码可以没有,不会出现问题,但是如果有此代码,再次进入该方法就可以减少判断。
_this.urlPrefixCache["delete"](prefixUrl);
return true;
} // 不超时
return false;
};
this.has = function (url) {
var prefixUrl = getPrefixUrl(url);
return !_this.isOverTime(prefixUrl);
};
this.isEmpty = function () {
return _this.urlPrefixCache.size === 0;
};
this.getCanUseUrl = function (loadUrls) {
var allUrls = loadUrls || [];
if (_this.isEmpty()) {
return allUrls[0] || '';
}
return allUrls.find(function (url) {
return !_this.has(url);
}) || '';
};
this.config = Object.assign({}, DEFAULT_OPTIONS, config);
if (this.config.strategy !== 'memory') {
return;
}
var urlPrefixCacheObj = this.getCacheFromStorage();
Object.keys(urlPrefixCacheObj).map(function (url) {
_this.urlPrefixCache.set(url, urlPrefixCacheObj[url]);
});
}
BadUrlPrefixCache.getInstance = function getInstance(config) {
if (!BadUrlPrefixCache.badUrlPrefixCache) {
BadUrlPrefixCache.badUrlPrefixCache = new BadUrlPrefixCache(config);
}
return BadUrlPrefixCache.badUrlPrefixCache;
};
var _proto = BadUrlPrefixCache.prototype;
_proto.setStorageForCache = function setStorageForCache() {
var _getStorage2;
var storageObj = {};
this.urlPrefixCache.forEach(function (value, key) {
storageObj[key] = value;
});
(_getStorage2 = getStorage(this.config.storageKey || '')) == null ? void 0 : _getStorage2.setItem(this.config.storageKey || STORAGE_KEY, JSON.stringify(storageObj));
};
return BadUrlPrefixCache;
}();
BadUrlPrefixCache.badUrlPrefixCache = null;
BadUrlPrefixCache.resetInstance = function (config) {
BadUrlPrefixCache.badUrlPrefixCache = null;
BadUrlPrefixCache.getInstance(config);
};
var setBadUrlPrefixCacheOptions = function setBadUrlPrefixCacheOptions(options) {
BadUrlPrefixCache.resetInstance(options);
};
var badUrlPrefixCache = /*#__PURE__*/BadUrlPrefixCache.getInstance({
strategy: 'localStorage'
});
var resloveCanUseUrl = function resloveCanUseUrl(moduleAssets) {
var allUrls = (moduleAssets || {}).loadUrls || [];
return badUrlPrefixCache.getCanUseUrl(allUrls);
};
var isModuleAssets = function isModuleAssets(item) {
return 'name' in item && 'loadUrls' in item;
};
/**
*
* @param needLoadItems
* @returns
*/
var moduleRetryLoad = function moduleRetryLoad(needLoadItems) {
return new Promise(function (resolve, reject) {
var startLoad = function startLoad(urls) {
return loadjs(urls, {
returnPromise: true
}).then(function () {
// Remove bad urls after success
urls.forEach(function (url) {
return badUrlPrefixCache["delete"](url);
});
resolve('success');
})["catch"](function (failUrls) {
// add bad urls after failure
urls.forEach(function (url) {
return badUrlPrefixCache.add(url);
});
var retryUrls = [];
var _loop = function _loop(i, len) {
var failUrl = failUrls[i]; // find module that fail to load and check for alternative urls
var failItem = needLoadItems.find(function (item) {
return item.url === failUrl;
});
if (!failItem || !failItem.moduleAssets) {
return {
v: void 0
};
}
var newUrl = resloveCanUseUrl(failItem.moduleAssets); // there is no url that can be replaced, and an error is reported directly
if (!newUrl) {
failItem.moduleAssets.status = 'fail';
reject(new Error("Cannot load assets " + failItem.moduleAssets.name + " " + newUrl));
return {
v: void 0
};
}
retryUrls.push(newUrl);
};
for (var i = 0, len = failUrls.length; i < len; i++) {
var _ret = _loop(i);
if (typeof _ret === "object") return _ret.v;
} // retry until successful or all urls fail
startLoad(retryUrls);
});
};
var urlsToLoad = needLoadItems.map(function (x) {
return x.url;
});
startLoad(urlsToLoad);
});
};
var cacheJsModules = {};
var deferred = /*#__PURE__*/createDeferredPromise();
var addJsModule = function addJsModule(module) {
!!module ? invariant(false, 'module cannot empty') : void 0;
var name = module.name,
loadUrls = module.loadUrls;
!!name ? invariant(false, 'module name cannot empty') : void 0;
!(!Array.isArray(loadUrls) || !loadUrls.length) ? invariant(false, 'module loadUrls cannot empty') : void 0;
if (cacheJsModules[name]) {
return false;
}
module.status = 'ready';
cacheJsModules[name] = module;
return true;
};
var startLoad = function startLoad(jsAssets, isAssetsList, time) {
if (time === void 0) {
time = 1;
}
var loadItems = jsAssets.map(function (name) {
var assets = cacheJsModules[name];
var item = {
moduleAssets: assets,
result: getWrapperDataFromGlobal(name)
};
if (!item.result) {
item.url = resloveCanUseUrl(assets);
}
return item;
});
var currentNeedLoadItems = loadItems.filter(function (item) {
return !item.result;
});
if (!currentNeedLoadItems.length) {
deferred.resolve(isAssetsList ? loadItems.map(function (item) {
return item.result;
}) : loadItems[0].result);
return;
}
var errIndex = currentNeedLoadItems.findIndex(function (item) {
return item.moduleAssets.status === 'fail';
});
if (errIndex > -1) {
deferred.reject("Cannot load assets " + currentNeedLoadItems[errIndex].moduleAssets.name);
return;
}
var loadingItems = currentNeedLoadItems.filter(function (item) {
return item.moduleAssets.status === 'loading';
});
if (loadingItems.length === currentNeedLoadItems.length) {
if (time > 10) {
deferred.reject("load assets overtime");
return;
}
setTimeout(function () {
startLoad(jsAssets, isAssetsList, time + 1);
}, time * 100);
}
var needLoadItems = currentNeedLoadItems.filter(function (item) {
return item.moduleAssets.status !== 'loading';
});
needLoadItems.forEach(function (item) {
return item.moduleAssets.status = 'loading';
});
return moduleRetryLoad(needLoadItems).then(function () {
needLoadItems.forEach(function (item) {
item.moduleAssets.status = 'success';
if (!item.moduleAssets.ready) {
item.result = getWrapperDataFromGlobal(item.moduleAssets.name);
return;
}
item.moduleAssets.ready.apply(item.moduleAssets);
item.result = getWrapperDataFromGlobal(item.moduleAssets.name);
});
if (loadingItems.length > 0) {
startLoad(jsAssets, isAssetsList, time + 1);
return;
}
deferred.resolve(isAssetsList ? loadItems.map(function (item) {
return item.result;
}) : loadItems[0].result);
});
};
var loadJsModule = function loadJsModule(jsAssets) {
var isAssetsList = true;
if (typeof jsAssets === 'string') {
jsAssets = [jsAssets];
isAssetsList = false;
} else if (isModuleAssets(jsAssets)) {
addJsModule(jsAssets);
jsAssets = [jsAssets.name];
isAssetsList = false;
}
var notFound = jsAssets.find(function (x) {
return !cacheJsModules[x];
});
!!!notFound ? invariant(false, "Cannot found assets " + notFound) : void 0;
startLoad(jsAssets, isAssetsList);
return deferred.currentPromise;
};
var cacheCssModules = {};
var addCssModule = function addCssModule(module) {
!!module ? invariant(false, 'module cannot empty') : void 0;
var name = module.name,
loadUrls = module.loadUrls;
!!name ? invariant(false, 'module name cannot empty') : void 0;
!(!Array.isArray(loadUrls) || !loadUrls.length) ? invariant(false, 'module loadUrls cannot empty') : void 0;
if (cacheCssModules[name]) {
return false;
}
module.status = 'ready';
cacheCssModules[name] = module;
return true;
};
var startLoad$1 = function startLoad(cssAssets) {
var loadItems = cssAssets.map(function (name) {
var assets = cacheCssModules[name];
return {
moduleAssets: assets,
url: resloveCanUseUrl(assets)
};
});
var needLoadItems = loadItems.filter(function (item) {
return ['loading', 'success'].includes(item.moduleAssets.status);
});
needLoadItems.forEach(function (item) {
return item.moduleAssets.status = 'loading';
});
return moduleRetryLoad(needLoadItems).then(function () {
needLoadItems.forEach(function (item) {
item.moduleAssets.status = 'success';
});
});
};
/**
*
* @param cssAssets
* @returns
*/
var loadCssAssets = function loadCssAssets(cssAssets) {
var notFound = cssAssets.find(function (x) {
return !cacheCssModules[x];
});
!!!notFound ? invariant(false, "Cannot found assets " + notFound) : void 0;
startLoad$1(cssAssets);
};
exports.loadjs = loadjs;
exports.addCssModule = addCssModule;
exports.addJsModule = addJsModule;
exports.loadCssAssets = loadCssAssets;
exports.loadJsModule = loadJsModule;
exports.setBadUrlPrefixCacheOptions = setBadUrlPrefixCacheOptions;
//# sourceMappingURL=static-assets-loader.cjs.development.js.map