UNPKG

hel-micro

Version:

A module federation SDK which is unrelated to tool chain for module consumer.

1,241 lines (1,214 loc) 167 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var helLibProxy = require('hel-lib-proxy'); var core$1 = require('hel-micro-core'); var helHtmlParser = require('hel-html-parser'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var helLibProxy__default = /*#__PURE__*/_interopDefaultLegacy(helLibProxy); var core__namespace = /*#__PURE__*/_interopNamespace(core$1); var VER$1 = '4.14.2'; /** * 暴露给 hel-micro 的 ui 对接层使用,例如 hel-micro-react 的 renderApp 接口,应用提供者会调用对接层开发者提供的 * renderApp接口渲染整个应用,当应用非本地运行时,renderApp不触发渲染逻辑而是调用 emitApp 弹射整个根应用出去 * 这样使用方可通过 react ui 对接层 的 <MicroApp name="xxApp" /> 来实例化整个远程应用 * * @see https://github.com/tnfe/hel/blob/main/packages/hel-micro-react/src/process/renderApp.tsx */ function emitApp$1(options) { var appGroupName = options.appGroupName, Comp = options.Comp, platform = options.platform, lifecycle = options.lifecycle, appName = options.appName, versionId = options.versionId; core$1.appReady(appGroupName, Comp, { lifecycle: lifecycle, platform: platform, appName: appName, versionId: versionId }); } /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } var toExport$2 = { LS_CACHE_APP_PREFIX: 'HelAppCache', // indexedDB 数据库名称 DATABASE_NAME: 'HelIndexedDB', // ObjectStore 名称 STORE_NAME: 'HelMetaData', }; // 保存db实例 var dbContexts = {}; /** * 创建 dbcontext * @returns */ function createContext() { return { db: null, name: '', storeName: '', version: 1, }; } /** * 获取indexedDB,若浏览器不支持则打印警告并返回 null * @returns */ function getIndexedDBFactory() { var gs = core$1.getGlobalThis(); if (!('indexedDB' in gs)) { console.warn('The current browser is not support indexedDB!'); return null; } return gs.indexedDB; } var IndexedDBStorage = /** @class */ (function () { function IndexedDBStorage(options) { this.dbInfo = createContext(); this.ready = null; this.initStorage(options); } IndexedDBStorage.prototype.initStorage = function (options) { var indexedDB = getIndexedDBFactory(); if (!indexedDB) return; var initResolve = null; var initReject = null; this.ready = new Promise(function (resolve, reject) { initResolve = resolve; initReject = reject; }); var dbInfo = this.dbInfo; if (options) { var name = options.name, storeName = options.storeName, version = options.version; Object.assign(dbInfo, core$1.commonUtil.purify({ name: name, storeName: storeName, version: version })); } var dbContext = dbContexts[dbInfo.name]; if (!dbContext) { dbContext = createContext(); dbContexts[dbInfo.name] = dbContext; } dbInfo.db = dbContext.db; // 是否升级 var isUpgrade = this.isUpgradeNeeded(dbInfo); if (dbInfo.db) { if (isUpgrade) { // 升级前关闭原来打开的 dbInfo.db.close(); } else { initResolve(dbInfo); return; } } var dbArgs = [dbInfo.name, undefined]; if (isUpgrade) { dbArgs[1] = dbInfo.version; } // 打开数据库 var openreq = indexedDB.open.apply(indexedDB, dbArgs); if (isUpgrade) { // 如果升级则监听 onupgradeneeded 事件 openreq.onupgradeneeded = function (e) { dbContext.db = openreq.result; dbInfo.db = openreq.result; try { // 创建 ojectStore(只能在 onupgradeneeded 事件中创建) dbInfo.db.createObjectStore(dbInfo.storeName); } catch (err) { // storeName 可能重复 if (err.name === 'ConstraintError') { var tip = core$1.commonUtil.nbstr("\n The database \"".concat(dbInfo.name, "\"\n has been upgraded from version ").concat(e.oldVersion, " to version ").concat(e.newVersion, ",\n but the storage \"").concat(dbInfo.storeName, "\" already exists.")); console.warn(tip); } else { throw err; } } }; } openreq.onerror = function () { initReject(openreq.error); }; openreq.onsuccess = function () { dbInfo.db = openreq.result; dbContext.db = openreq.result; dbInfo.db.onversionchange = function (e) { e.target.close(); }; initResolve(dbInfo); }; }; /** * 判断是否升级 * @param dbInfo * @returns */ IndexedDBStorage.prototype.isUpgradeNeeded = function (dbInfo) { if (!dbInfo.db) return true; // 是否有新的 objectStore var isNewStore = !dbInfo.db.objectStoreNames.contains(dbInfo.storeName); // 是否降低版本 var isDowngrade = dbInfo.version < dbInfo.db.version; // 是否升级版本 var isUpgrade = dbInfo.version > dbInfo.db.version; if (isDowngrade) { // 对于降低版本给予提示,并继续采用之前的版本 console.warn("The database \"".concat(dbInfo.name, "\" can't be downgraded from version ").concat(dbInfo.db.version, " to version ").concat(dbInfo.version)); dbInfo.version = dbInfo.db.version; } if (isUpgrade || isNewStore) { // 有新的 objectStore 则升级版本 if (isNewStore) { var incVersion = dbInfo.db.version + 1; if (incVersion > dbInfo.version) { dbInfo.version = incVersion; } } return true; } return false; }; IndexedDBStorage.prototype.getObjectStore = function (dbInfo, mode) { var name = dbInfo.name, db = dbInfo.db, storeName = dbInfo.storeName; if (!db) { throw new Error("get ".concat(storeName, " objectStore failed in ").concat(name, " database")); } var objectStore = db.transaction(storeName, mode || 'readonly').objectStore(storeName); return objectStore; }; IndexedDBStorage.prototype.attachHandler = function (req, resolve, reject) { req.onsuccess = function () { resolve(req.result || null); }; req.onerror = function () { reject(req.error); }; }; IndexedDBStorage.prototype.getItem = function (key) { return __awaiter(this, void 0, void 0, function () { var dbInfo, objectStore, req; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getDbInfo()]; case 1: dbInfo = _a.sent(); objectStore = this.getObjectStore(dbInfo); req = objectStore.get(key); return [2 /*return*/, new Promise(function (resolve, reject) { _this.attachHandler(req, resolve, reject); })]; } }); }); }; IndexedDBStorage.prototype.setItem = function (key, value) { return __awaiter(this, void 0, void 0, function () { var dbInfo, objectStore, req; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getDbInfo()]; case 1: dbInfo = _a.sent(); objectStore = this.getObjectStore(dbInfo, 'readwrite'); req = objectStore.put(value, key); return [2 /*return*/, new Promise(function (resolve, reject) { _this.attachHandler(req, resolve, reject); })]; } }); }); }; IndexedDBStorage.prototype.removeItem = function (key) { return __awaiter(this, void 0, void 0, function () { var dbInfo, objectStore, req; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getDbInfo()]; case 1: dbInfo = _a.sent(); objectStore = this.getObjectStore(dbInfo, 'readwrite'); req = objectStore.delete(key); return [2 /*return*/, new Promise(function (resolve, reject) { _this.attachHandler(req, resolve, reject); })]; } }); }); }; IndexedDBStorage.prototype.getDbInfo = function () { if (!this.ready) { return Promise.reject('forget init'); } return this.ready; }; return IndexedDBStorage; }()); function isRelativePath(path) { if (path.startsWith('//')) return false; return path.startsWith('/') || path.startsWith('./') || path.startsWith('../'); } function getAssetUrlType(webDirPath, url) { if (url.startsWith(webDirPath)) { return 'build'; // 是构建生成的 css 文件 } if (isRelativePath(url)) { return 'relative'; } return 'static'; } function getIndexedDB() { if (!getIndexedDBFactory()) return null; try { var indexedDBIns_1 = new IndexedDBStorage({ name: toExport$2.DATABASE_NAME, storeName: toExport$2.STORE_NAME, }); return { setItem: function (key, value) { return indexedDBIns_1.setItem(key, value); }, getItem: function (key) { return indexedDBIns_1.getItem(key); }, removeItem: function (key) { return indexedDBIns_1.removeItem(key); }, }; } catch (err) { console.error("new IndexedDBStorage error: ".concat(err.message)); return null; } } // avoid mock js-dom warn: // [DOMException [SecurityError]: localStorage is not available for opaque origins] function getLocalStorage() { var _a; // prettier-ignore var mockStorage = { getItem: function () { }, setItem: function () { }, removeItem: function () { } }; try { var storage = (_a = core$1.getGlobalThis()) === null || _a === void 0 ? void 0 : _a.localStorage; return storage || mockStorage; } catch (err) { return mockStorage; } } /** * 支持读取 dom attrs 时只有 key 的正确含义 * 例如通过设定 defaultValIfOnlyKey 表示 <script data-helappend /> 可拿到值为 '1' 而非 '' */ function getDatasetVal(dataset, key, defaultValIfOnlyKey) { var hasKey = Object.prototype.hasOwnProperty.call(dataset, key); if (hasKey) { return dataset[key] || defaultValIfOnlyKey; } return undefined; } function getPlatform(platform) { return platform || core__namespace.getPlatform(); } function saveToLocalStorage(cacheKey, toSave) { try { getLocalStorage().setItem(cacheKey, JSON.stringify(toSave)); } catch (err) { core$1.log("save localStorage failed: ".concat(err.message)); } } /** * 获取缓存应用元数据的key */ function getAppCacheKey$1(appName, platform) { var innerKey = "".concat(toExport$2.LS_CACHE_APP_PREFIX, ".").concat(getPlatform(platform), ".").concat(appName); return innerKey; } /** * 获取缓存的应用元数据 */ function getCachedAppMeta$1(appName, options) { return __awaiter(this, void 0, Promise, function () { var _a, platform, cacheKey, _b, storageType, appCacheKey, indexedDBStorage, appCache, appCacheStr, err_1; return __generator(this, function (_c) { switch (_c.label) { case 0: _a = options || {}, platform = _a.platform, cacheKey = _a.cacheKey, _b = _a.storageType, storageType = _b === void 0 ? 'indexedDB' : _b; appCacheKey = cacheKey || getAppCacheKey$1(appName, platform); _c.label = 1; case 1: _c.trys.push([1, 4, , 5]); if (!(storageType === 'indexedDB')) return [3 /*break*/, 3]; indexedDBStorage = getIndexedDB(); if (!indexedDBStorage) return [3 /*break*/, 3]; return [4 /*yield*/, indexedDBStorage.getItem(appCacheKey)]; case 2: appCache = _c.sent(); return [2 /*return*/, appCache]; case 3: appCacheStr = getLocalStorage().getItem(appCacheKey); return [2 /*return*/, core$1.commonUtil.safeParse(appCacheStr || '', null)]; case 4: err_1 = _c.sent(); console.error(err_1); return [2 /*return*/, null]; case 5: return [2 /*return*/]; } }); }); } function innerGetAppCacheKey(appName, getCacheKey, platform) { var innerKey = getAppCacheKey$1(appName, platform); var key = (getCacheKey === null || getCacheKey === void 0 ? void 0 : getCacheKey({ appName: appName, innerKey: innerKey })) || innerKey; return key; } function innerGetDiskCachedApp(appName, options) { return __awaiter(this, void 0, Promise, function () { var getCacheKey, storageType, platform, cacheKey, meta; return __generator(this, function (_a) { switch (_a.label) { case 0: getCacheKey = options.getCacheKey, storageType = options.storageType, platform = options.platform; cacheKey = innerGetAppCacheKey(appName, getCacheKey, platform); return [4 /*yield*/, getCachedAppMeta$1(appName, { platform: platform, cacheKey: cacheKey, storageType: storageType })]; case 1: meta = _a.sent(); if (meta) { return [2 /*return*/, { appInfo: meta.app, appVersion: meta.version }]; } return [2 /*return*/, null]; } }); }); } function innerSaveMetaToDisk(cacheKey, toSave, storageType) { var isSaveToIndexedDB = storageType === 'indexedDB'; if (!isSaveToIndexedDB) { return saveToLocalStorage(cacheKey, toSave); } var indexedDBStorage = getIndexedDB(); if (!indexedDBStorage) { return saveToLocalStorage(cacheKey, toSave); } indexedDBStorage.setItem(cacheKey, toSave).catch(function (err) { core$1.log("save indexeddb failed, use localStorage instead, err: ".concat(err.message)); saveToLocalStorage(cacheKey, toSave); }); } /** api 服务模块的相关常量 */ var apiSrvConst = { GET_APP_AND_VER: 'getSubAppAndItsVersion', GET_APP_AND_FULL_VER: 'getSubAppAndItsFullVersion', BATCH_GET_APP_AND_VER: 'batchGetSubAppAndItsVersion', BATCH_GET_APP_AND_FULL_VER: 'batchGetSubAppAndItsFullVersion', GET_APP_VER: 'getSubAppVersion', GET_APP_FULL_VER: 'getSubAppFullVersion', }; var API_NORMAL_GET = 'get'; var JSONP_MARK = 'Jsonp'; function getUserName(options) { var userLsKey = options.userLsKey; var userName = getLocalStorage().getItem(userLsKey) || ''; if (userName) { return userName; } try { var map_1 = {}; core$1.getGlobalThis() .document.cookie.split(';') .forEach(function (kvStr) { var _a = kvStr.split('='), k = _a[0], v = _a[1]; map_1[k] = v; }); userName = map_1[userLsKey] || ''; core$1.log('[[ getUserName ]] result:', userName); } catch (err) { core$1.log('[[ getUserName ]] err:', err); } return userName; } var builtinFns = /*#__PURE__*/Object.freeze({ __proto__: null, getUserName: getUserName }); var isNull = core$1.commonUtil.isNull; function getFn(platform, fnName, userFn) { var conf = core$1.getPlatformConfig(platform); var origin = conf.origin; var confFn = conf[fnName]; // @ts-ignore var originFn = origin[fnName]; return userFn || confFn || originFn; } function callFn(platform, fnName, params, userFn) { var fn = getFn(platform, fnName, userFn); if (fn) { return fn(params); } // @ts-ignore var builtinFn = builtinFns[fnName] || (function () { return null; }); return builtinFn(params); } function getVal(platform, key, valPair, nullDef) { var _a = valPair || [], userVal = _a[0], defaultVal = _a[1]; if (!isNull(userVal, nullDef)) { return userVal; } var conf = core$1.getPlatformConfig(platform); // 优先返回 platInitOptions var confVal = conf[key]; if (!isNull(confVal, nullDef)) { return confVal; } // 最后返回 originInitOptions var origin = conf.origin; // @ts-ignore var originVal = origin[key]; if (!isNull(originVal, nullDef)) { return originVal; } return defaultVal; } function getHookFn(loadOptions, hookKey) { var _a; var conf = core$1.getPlatformConfig(loadOptions.platform); var userHook = loadOptions.hook || {}; var origin = conf.origin, hook = conf.hook; return userHook[hookKey] || hook[hookKey] || ((_a = origin.hook) === null || _a === void 0 ? void 0 : _a[hookKey]); } /** * 按下面 'getApiPrefix' 链接里描述的生成规则生成api域名前缀 * @type {import('hel-micro-core').IControlPreFetchOptions['getApiPrefix']} * @param platform * @param loadOptions * @returns */ function genApiPrefix(platform, loadOptions) { var _a, _b, _c; var prefix = ''; if (loadOptions) { prefix = ((_a = loadOptions.getApiPrefix) === null || _a === void 0 ? void 0 : _a.call(loadOptions)) || loadOptions.apiPrefix; } if (prefix) { return prefix; } var conf = core$1.getPlatformConfig(platform); prefix = ((_b = conf.getApiPrefix) === null || _b === void 0 ? void 0 : _b.call(conf)) || conf.apiPrefix; if (prefix) { return prefix; } var origin = conf.origin; prefix = ((_c = origin.getApiPrefix) === null || _c === void 0 ? void 0 : _c.call(origin)) || origin.apiPrefix; return prefix; } // @see https://www.runoob.com/jsref/prop-node-nodetype.html var DOCUMENT_FRAGMENT_NODE = 11; var JSONP = { now: function () { return new Date().getTime(); }, rand: function () { return Math.random().toString().substring(6); }, // 删除节点元素 removeElem: function (elem) { var parent = elem.parentNode; if (parent && parent.nodeType !== DOCUMENT_FRAGMENT_NODE) { parent.removeChild(elem); } }, // url 组装 data parseData: function (data) { var ret = ''; if (typeof data === 'string') { ret = data; } else if (typeof data === 'object') { for (var key in data) { ret += "".concat(ret, "&").concat(key, "=").concat(encodeURIComponent(data[key])); } } // 加时间戳防止缓存 ret += "&_t=".concat(JSONP.now()); ret = ret.substring(1); return ret; }, getJSON: function (inputUrl, data) { return new Promise(function (resolve, reject) { var callbackName = ''; var url = inputUrl; url = url + (url.indexOf('?') === -1 ? '?' : '&') + JSONP.parseData(data); // 检测 callback 的函数名是否已经定义 var match = /callback=(\w+)/.exec(url); if (match === null || match === void 0 ? void 0 : match[1]) { callbackName = match[1]; } else { callbackName = "helJsonp_".concat(JSONP.now(), "_").concat(JSONP.rand()); } if (url.includes('?')) { url = "".concat(url, "&callback=").concat(callbackName); } else { url = "".concat(url, "?callback=").concat(callbackName); } var globalThis = core$1.getGlobalThis(); var doc = globalThis.document; var script = doc.createElement('script'); script.type = 'text/javascript'; script.src = url; script.id = callbackName; script.onerror = reject; script.addEventListener('error', reject); // 早期版本的浏览器不支持 script.onerror // 把传进来的函数重新组装,并把它设置为全局函数,远程会触发该函数 // @ts-ignore globalThis[callbackName] = function (jsonData) { // @ts-ignore delete globalThis[callbackName]; // 执行完函数就销毁 var elem = doc.getElementById(callbackName); elem && JSONP.removeElem(elem); return resolve(jsonData); }; var head = doc.getElementsByTagName('head'); if (head === null || head === void 0 ? void 0 : head[0]) { head[0].appendChild(script); } }); }, }; var getJSON = JSONP.getJSON; function getXHRFactory() { if (!('XMLHttpRequest' in core$1.getGlobalThis())) { return null; } return new XMLHttpRequest(); } function xhrFetch(url, config) { return __awaiter(this, void 0, Promise, function () { var _a, method, xhrConfig, xhr, result; return __generator(this, function (_b) { switch (_b.label) { case 0: _a = config || {}, method = _a.method, xhrConfig = __rest(_a, ["method"]); xhr = new XHR(xhrConfig); return [4 /*yield*/, xhr.request(url, method)]; case 1: result = _b.sent(); return [2 /*return*/, result]; } }); }); } var XHR = /** @class */ (function () { function XHR(config) { this.req = null; this.resultPromise = Promise.resolve(null); this.init(config || {}); } XHR.prototype.init = function (config) { var req = getXHRFactory(); if (!req) { throw new Error('current browser is not support XMLHttpRequest!'); } this.req = req; // 同步配置 var responseType = config.responseType, _a = config.timeout, timeout = _a === void 0 ? 10000 : _a, withCredentials = config.withCredentials, headers = config.headers; req.responseType = responseType || 'json'; req.timeout = timeout; req.withCredentials = !!withCredentials; if (headers) { Object.keys(headers).forEach(function (key) { req.setRequestHeader(key, headers[key]); }); } var initResolve = null; var initReject = null; this.resultPromise = new Promise(function (resolve, reject) { initResolve = resolve; initReject = reject; }); var wrapSuccessResult = function () { var response = req.response, status = req.status, statusText = req.statusText, responseURL = req.responseURL; initResolve({ data: response, status: status, statusText: statusText, url: responseURL }); }; var wrapErrResult = function (e) { var status = req.status, statusText = req.statusText, responseURL = req.responseURL; initReject({ msg: e, status: status, statusText: statusText, url: responseURL }); }; // 监听事件 req.onload = function () { return wrapSuccessResult(); }; req.onerror = function (e) { return wrapErrResult(e); }; req.onabort = function (e) { return wrapErrResult(e); }; req.ontimeout = function (e) { return wrapErrResult(e); }; req.onprogress = function () { }; }; XHR.prototype.request = function (url, method) { return __awaiter(this, void 0, Promise, function () { var result; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!this.req) { throw new Error('forget init'); } // 发送请求 this.req.open(method ? method.toUpperCase() : 'GET', url); this.req.send(); return [4 /*yield*/, this.resultPromise]; case 1: result = _a.sent(); return [2 /*return*/, result]; } }); }); }; return XHR; }()); var seq = 0; var detectMark = 'try_detect_latest_ver'; function hasProp(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } function perfStart(label, addSeq) { var seqStr = ''; if (core$1.allowLog()) { if (addSeq) { seq += 1; seqStr = "_".concat(seq); } console.time("".concat(label).concat(seqStr)); } return seqStr; } function perfEnd(label, seq) { if (core$1.allowLog()) { console.timeEnd("".concat(label).concat(seq || '')); } } /** * 默认请求 unpkg,会先经过 302 重定向到一个 404 请求地址后,即可拿到最新的版本号 */ function getSemverLatestVer(appName, apiPrefix) { return __awaiter(this, void 0, void 0, function () { var url, strArr, includeVerStr, ver, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, requestGet("".concat(apiPrefix, "/").concat(appName, "@latest/").concat(detectMark, "_").concat(Date.now()))]; case 1: url = (_a.sent()).url; strArr = url.split('@'); includeVerStr = strArr[strArr.length - 1]; ver = includeVerStr.split('/')[0]; return [2 /*return*/, ver]; case 2: err_1 = _a.sent(); core$1.log('[[ getSemverLatestVer ]] returns ver(latest) due to error:', err_1.message); return [2 /*return*/, 'latest']; case 3: return [2 /*return*/]; } }); }); } function requestByFetch(url, asJson) { return __awaiter(this, void 0, void 0, function () { var res, status, resUrl, json, text; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, core$1.getGlobalThis().fetch(url)]; case 1: res = _a.sent(); status = res.status, resUrl = res.url; if (![200, 304].includes(status)) { return [2 /*return*/, { url: resUrl, reply: null, status: status }]; } if (!asJson) return [3 /*break*/, 3]; return [4 /*yield*/, res.json()]; case 2: json = _a.sent(); return [2 /*return*/, { url: resUrl, reply: json, status: status }]; case 3: return [4 /*yield*/, res.text()]; case 4: text = _a.sent(); return [2 /*return*/, { url: resUrl, reply: text, status: status }]; } }); }); } function requestByXHR(url, asJson) { return __awaiter(this, void 0, void 0, function () { var res, status, data, _a, resUrl; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, xhrFetch(url, { method: 'GET', responseType: asJson ? 'json' : 'text' })]; case 1: res = _b.sent(); status = res.status, data = res.data, _a = res.url, resUrl = _a === void 0 ? '' : _a; if (status === 400) { return [2 /*return*/, { url: resUrl, reply: null, status: status }]; } return [2 /*return*/, { url: resUrl, reply: data, status: status }]; } }); }); } function requestGet(url, asJson) { if (asJson === void 0) { asJson = true; } return __awaiter(this, void 0, void 0, function () { var requester, result; return __generator(this, function (_a) { switch (_a.label) { case 0: requester = requestByXHR; // 如果支持fetch则使用 if (!!core$1.getGlobalThis().fetch) { requester = requestByFetch; } return [4 /*yield*/, requester(url, asJson)]; case 1: result = _a.sent(); return [2 /*return*/, result]; } }); }); } function getAllExtraCssList(loadOptions) { var _a = loadOptions.extraCssList, extraCssList = _a === void 0 ? [] : _a, custom = loadOptions.custom; if (custom) { var _b = custom.extraCssList, custCssList = _b === void 0 ? [] : _b, _c = custom.enable, enable = _c === void 0 ? true : _c; if (enable) { var mergedList = core$1.commonUtil.merge2List(extraCssList, custCssList); return mergedList; } } return extraCssList.slice(); } var safeParse = core$1.commonUtil.safeParse; /** 内部用的工具函数 */ var inner$3 = { /** 处理语义化版本平台返回的结果 */ handleSemverRet: function (ret, options) { var version = (ret || {}).version; var retVar = ret; if (options.onlyVersion) { retVar = version; } if (!options.isFullVersion && version) { Reflect.deleteProperty(version, 'html_content'); } if (!version) { return { data: null, code: '404', msg: 'no version found' }; } return { data: retVar, code: '0', msg: '' }; }, appendSearchKV: function (oriStr, key, value) { var newStr = oriStr; if (value) { newStr += "&".concat(key, "=").concat(value); } return newStr; }, appendSuffix: function (oriStr, suffix) { var newStr = oriStr; if (suffix) { newStr += suffix; } return newStr; }, }; function executeGet(url, options) { return __awaiter(this, void 0, Promise, function () { var ret, _a, semverApi, apiMode, perfLabel, result, err_1; return __generator(this, function (_b) { switch (_b.label) { case 0: ret = null; _a = options.semverApi, semverApi = _a === void 0 ? true : _a; apiMode = semverApi ? API_NORMAL_GET : options.apiMode; perfLabel = "request ".concat(url); perfStart(perfLabel); _b.label = 1; case 1: _b.trys.push([1, 6, , 7]); if (!(apiMode === API_NORMAL_GET)) return [3 /*break*/, 3]; return [4 /*yield*/, requestGet(url)]; case 2: result = _b.sent(); ret = result.reply; return [3 /*break*/, 5]; case 3: return [4 /*yield*/, getJSON(url)]; case 4: // jsonp get ret = _b.sent(); _b.label = 5; case 5: perfEnd(perfLabel); // 请求语义化cdn平台时拿到的是原始数据,和自定义平台有差异 // 这里做一下抹平处理,以便上层可以用一致的方式读取数据 if (semverApi) { return [2 /*return*/, inner$3.handleSemverRet(ret, options)]; } return [2 /*return*/, ret]; case 6: err_1 = _b.sent(); perfEnd(perfLabel); return [2 /*return*/, { data: null, code: '404', msg: err_1.message }]; case 7: return [2 /*return*/]; } }); }); } function ensureApp(app) { var clonedApp = __assign({}, app); clonedApp.additional_scripts = safeParse(clonedApp.additional_scripts, []); clonedApp.additional_body_scripts = safeParse(clonedApp.additional_body_scripts, []); return clonedApp; } function ensureVersion(version) { var clonedVersion = __assign({}, version); clonedVersion.src_map = safeParse(clonedVersion.src_map, { htmlIndexSrc: '', webDirPath: '', headAssetList: [], bodyAssetList: [], chunkJsSrcList: [], chunkCssSrcList: [], staticJsSrcList: [], staticCssSrcList: [], relativeJsSrcList: [], relativeCssSrcList: [], otherSrcList: [], }); return clonedVersion; } /** * 生成版本语义化的元数据请求链接 */ function getSemverUrl(apiHost, appName, versionId, skip404Sniff) { if (skip404Sniff === void 0) { skip404Sniff = false; } return __awaiter(this, void 0, void 0, function () { var ver; return __generator(this, function (_a) { switch (_a.label) { case 0: ver = versionId; if (!!ver) return [3 /*break*/, 3]; if (!skip404Sniff) return [3 /*break*/, 1]; ver = 'latest'; // latest 未必是最新的,unpkg 可能有延时,需用户自己抉择需不需要跳过404嗅探 return [3 /*break*/, 3]; case 1: return [4 /*yield*/, getSemverLatestVer(appName, apiHost)]; case 2: ver = _a.sent(); _a.label = 3; case 3: // https://unpkg.com/hel-lodash@2.1.7/hel_dist/hel-meta.json // https://cdn.jsdelivr.net/npm/hel-lodash@2.1.7/hel_dist/hel-meta.json return [2 /*return*/, "".concat(apiHost, "/").concat(appName, "@").concat(ver, "/hel_dist/hel-meta.json?_t=").concat(Date.now())]; } }); }); } /** * 生成请求的自定义平台的请求信息 */ function prepareCustomPlatRequestInfo(appNameOrNames, getOptions) { var versionId = getOptions.versionId, projectId = getOptions.projectId, branchId = getOptions.branchId, apiMode = getOptions.apiMode, _a = getOptions.isFullVersion, isFullVersion = _a === void 0 ? false : _a, _b = getOptions.versionIdList, versionIdList = _b === void 0 ? [] : _b, _c = getOptions.projectIdList, projectIdList = _c === void 0 ? [] : _c, _d = getOptions.branchIdList, branchIdList = _d === void 0 ? [] : _d, _e = getOptions.loadOptions, loadOptions = _e === void 0 ? {} : _e; var platform = getPlatform(getOptions.platform); // trust me, appName will be reassign later var appName = appNameOrNames; var urlAppName = appName; var urlVersion = versionId; var urlProjId = projectId; var urlBranchId = branchId; var isBatch = false; if (Array.isArray(appNameOrNames)) { appName = appNameOrNames[0]; urlAppName = appNameOrNames.join(','); urlVersion = versionIdList.join(','); urlProjId = projectIdList.join(','); urlBranchId = branchIdList.join(','); isBatch = true; } // 按 preFetchOptions.{key} --> platInitOptions.{key} --> originInitOptions.{key} --> innerDefault 取值的函数 var getVal$1 = function (key, defaultVal) { return getVal(platform, key, [loadOptions[key], defaultVal]); }; var getFnVal = function (fnName, fnParams) { return callFn(platform, fnName, fnParams, loadOptions[fnName]); }; var userLsKey = getVal$1('userLsKey', core$1.helConsts.DEFAULT_USER_LS_KEY); var userName = getFnVal('getUserName', { platform: platform, appName: appName, userLsKey: userLsKey }); var grayResult = getFnVal('shouldUseGray', { appName: appName }); var apiSuffix = getVal$1('apiSuffix'); var grayVar = ''; if (typeof grayResult === 'boolean') { grayVar = grayResult ? '1' : '0'; } var isJsonpGet = apiMode !== API_NORMAL_GET; var url = ''; var interfaceName = ''; var hasV2Get = false; if (!isBatch) { var customMetaUrl = getVal$1('customMetaUrl', ''); var customMetaJsonpUrl = getVal$1('customMetaJsonpUrl', ''); if (customMetaUrl) { url = "".concat(customMetaUrl, "/").concat(appName, "?"); } else if (isJsonpGet && customMetaJsonpUrl) { url = "".concat(customMetaJsonpUrl, "/").concat(appName, "?"); } if (!url) { interfaceName = !isFullVersion ? apiSrvConst.GET_APP_AND_VER : apiSrvConst.GET_APP_AND_FULL_VER; } else { hasV2Get = true; } } else { interfaceName = !isFullVersion ? apiSrvConst.BATCH_GET_APP_AND_VER : apiSrvConst.BATCH_GET_APP_AND_FULL_VER; } if (!hasV2Get) { var apiPathOfApp = getVal$1('apiPathOfApp', core$1.helConsts.DEFAULT_API_URL); var apiHost = genApiPrefix(platform, loadOptions); // 为自定义模块管理台拼接请求链接 var jsonpMark = isJsonpGet ? JSONP_MARK : ''; var finalInterfaceName = "".concat(interfaceName).concat(jsonpMark); url = "".concat(apiHost).concat(apiPathOfApp, "/").concat(finalInterfaceName, "?name=").concat(urlAppName); } url = inner$3.appendSearchKV(url, 'userName', userName); url = inner$3.appendSearchKV(url, 'version', urlVersion); url = inner$3.appendSearchKV(url, 'projId', urlProjId); url = inner$3.appendSearchKV(url, 'branch', urlBranchId); url = inner$3.appendSearchKV(url, 'gray', grayVar); url = inner$3.appendSuffix(url, apiSuffix); if (url.endsWith('?')) { url = url.substring(0, url.length - 1); } return { url: url, userName: userName }; } /** * 生成请求语义化版本的请求信息( 如请求 unpkg jsdelivr ) */ function prepareSemverRequestInfo(appName, getOptions) { return __awaiter(this, void 0, void 0, function () { var versionId, platform, loadOptions, apiHost, url; return __generator(this, function (_a) { switch (_a.label) { case 0: versionId = getOptions.versionId, platform = getOptions.platform, loadOptions = getOptions.loadOptions; apiHost = genApiPrefix(platform, loadOptions); return [4 /*yield*/, getSemverUrl(apiHost, appName, versionId || '', loadOptions === null || loadOptions === void 0 ? void 0 : loadOptions.skip404Sniff)]; case 1: url = _a.sent(); return [2 /*return*/, url]; } }); }); } /** * 生成请求请求信息 */ function prepareRequestInfo(appName, getOptions) { var _a; return __awaiter(this, void 0, void 0, function () { var loadOptions, userName, url, semverApi, ret; return __generator(this, function (_b) { switch (_b.label) { case 0: loadOptions = getOptions.loadOptions; userName = ''; url = ''; semverApi = (_a = loadOptions === null || loadOptions === void 0 ? void 0 : loadOptions.semverApi) !== null && _a !== void 0 ? _a : true; if (!semverApi) return [3 /*break*/, 2]; return [4 /*yield*/, prepareSemverRequestInfo(appName, getOptions)]; case 1: url = _b.sent(); return [3 /*break*/, 3]; case 2: ret = prepareCustomPlatRequestInfo(appName, getOptions); url = ret.url; userName = ret.userName; _b.label = 3; case 3: return [2 /*return*/, { url: url, userName: userName }]; } }); }); } /** * 准备请求版本数据的 url 链接 */ function prepareRequestVersionUrl(versionId, getOptions) { return __awaiter(this, void 0, void 0, function () { var apiMode, appName, _a, isFullVersion, _b, semverApi, _c, apiPrefix, getUrl, platform, apiHost, apiSuffix, apiPathOfApp, apiPathOfAppVersion, url, jsonpMark, interfaceName, finalInterfaceName, finalApiPath; return __generator(this, function (_d) { switch (_d.label) { case 0: apiMode = getOptions.apiMode, appName = getOptions.appName, _a = getOptions.isFullVersion, isFullVersion = _a === void 0 ? false : _a, _b = getOptions.semverApi, semverApi = _b === void 0 ? true : _b, _c = getOptions.apiPrefix, apiPrefix = _c === void 0 ? '' : _c, getUrl = getOptions.getUrl; platform = getPlatform(getOptions.platform); apiHost = apiPrefix || getVal(platform, 'apiPrefix'); apiSuffix = getVal(platform, 'apiSuffix'); apiPathOfApp = getVal(platform, 'apiPathOfApp'); apiPathOfAppVersion = getVal(platform, 'apiPathOfAppVersion'); url = ''; if (!semverApi) return [3 /*break*/, 2]; return [4 /*yield*/, getSemverUrl(apiHost, appName, versionId)]; case 1: url = _d.sent(); return [3 /*break*/, 3]; case 2: jsonpMark = apiMode === API_NORMAL_GET ? '' : JSONP_MARK; interfaceName = !isFullVersion ? apiSrvConst.GET_APP_VER : apiSrvConst.GET_APP_FULL_VER; finalInterfaceName = "".concat(interfaceName).concat(jsonpMark); finalApiPath = apiPathOfAppVersion || apiPathOfApp || core$1.helConsts.DEFAULT_API_URL; url = "".concat(apiHost).concat(finalApiPath, "/").concat(finalInterfaceName, "?ver=").concat(versionId); url = inner$3.appendSearchKV(url, 'name', appName); url = inner$3.appendSuffix(url, apiSuffix); _d.label = 3; case 3: url = (getUrl === null || getUrl === void 0 ? void 0 : getUrl(url)) || url; return [2 /*return*/, url]; } }); }); } function extractMetaFromReply(appName, inputReply) { var reply = inputReply; // 支持 getMeta 按类型说明返回的 IHelMeta 结构 if (hasProp(reply, 'app') && hasProp(reply, 'version')) { reply = { code: 0, data: { app: reply.app, version: reply.version } }; } if (!reply || 0 !== Number(reply.code)) { throw new Error((reply === null || reply === void 0 ? void 0 : reply.msg) || 'getSubAppAndItsVersion err`'); } var _a = reply.data || {}, app = _a.app, version = _a.version; if (!app) { throw new Error("no app for ".concat(appName)); } if (!version) { // 可能存在有应用但无版本的情况 throw new Error("no version for ".concat(appName)); } return { app: ensureApp(app), version: ensureVersion(version) }; } /** * 获取子应用和它的最新在线版本 */ function getSubAppAndItsVersion(appName, getOptions) { return __awaiter(this, void 0, void 0, function () { var versionId, platform, apiMode, _a, loadOptions, oldFnName, newFnName, fnName, getMetaFn, _b, url, userName, innerRequest, needGrayVer, fnParams, data_1, meta, data; var _this = this; return __generator(this, function (_c) { switch (_c.label) { case 0: versionId = getOptions.versionId, platform = getOptions.platform, apiMode = getOptions.apiMode, _a = getOptions.loadOptions, loadOptions = _a === void 0 ? {} : _a; oldFnName = 'getSubAppAndItsVersionFn'; newFnName = 'getMeta'; fnName = newFnName; getMetaFn = getFn(platform, newFnName, loadOptions.getMeta); if (!getMetaFn) { // 兼容就配置项 getMetaFn = getFn(platform, oldFnName, loadOptions.getSubAppAndItsVersionFn); fnName = oldFnName; } return [4 /*yield*/, prepareRequestInfo(appName, getOptions)]; case 1: _b = _c.sent(), url = _b.url, userName = _b.userName; innerRequest = function (custUrl, custApiMode) { return __awaiter(_this, void 0, void 0, function () { var metaUrl, reply, meta; return __generator(this, function (_a) { switch (_a.label) { case 0: metaUrl = custUrl || url; return [4 /*yield*/, executeGet(metaUrl, { apiMode: custApiMode || apiMode, semverApi: loadOptions.semverApi })]; case 1: reply = _a.sent(); meta = extractMetaFromReply(appName, reply); return [2 /*return*/, meta]; } }); }); }; if (!getMetaFn) return [3 /*break*/, 3]; needGrayVer = callFn(platform, 'shouldUseGray', { appName: appName }, loadOptions.shouldUseGray); fnParams = { platform: platform, appName: appName, userName: userName, versionId: versionId, url: url, needGrayVer: needGrayVer, innerRequest: innerRequest }; core$1.log("[[ ".concat(fnName, " ]] fnParams:"), fnParams); return [4 /*yield*/, Promise.resolve(getMetaFn(fnParams))]; case 2: d