UNPKG

@foxpage/foxpage-manager

Version:

foxpage resource manager

403 lines (402 loc) 13.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CSRPluginManagerImpl = void 0; const foxpage_shared_1 = require("@foxpage/foxpage-shared"); const common_1 = require("../common"); const data_service_1 = require("../data-service"); const plugin_1 = require("./plugin"); /** * plugin manager for csr * * @export * @class CSRPluginManagerImpl * @implements {CSRPluginManager} */ class CSRPluginManagerImpl extends common_1.ManagerBaseImpl { constructor(app) { super(app, { type: 'plugin', diskCache: { enable: true }, lruCache: { cloned: false } }); /** * cache plugin name & versions * key: plugin name, value: version list * @private */ this.pluginVersionsMap = new Map(); /** * plugin id map * key: plugin id, value: plugin name * * @private */ this.pluginIdMap = new Map(); this.generateKey = (name, version) => { return foxpage_shared_1.packager.generateKey(name, version); }; this.splitKey = (key) => { return foxpage_shared_1.packager.splitKey(key); }; this.logger = (0, foxpage_shared_1.createLogger)('pluginManager'); this.resourceConfig = app.resourceMap; this.config = app.configs.package || {}; } /** * add plugin to manager * * @param {PrePackage} pkg */ addPlugin(pkg) { const { id, name, version } = pkg; this.logger.info(`add plugin ${name}@${version}`); if (!version) { this.logger.warn('plugin version is invalid'); return null; } const newPkg = this.newPlugin(pkg); this.addOne(newPkg.key, pkg, newPkg); this.updatePluginVersionsMap(pkg); this.updatePluginLiveVersion(pkg); this.pluginIdMap.set(id, name); return newPkg; } /** * remove plugin from manager via plugin names * * @param {string[]} names plugin names */ removePlugins(names) { const versionInfo = this.getPluginVersionsByNames(names); Object.keys(versionInfo).forEach(name => { var _a; const versions = versionInfo[name]; if (versions) { this.remove(versions.map(item => this.generateKey(name, item))); } const pluginId = (_a = this.pluginVersionsMap.get(name)) === null || _a === void 0 ? void 0 : _a.id; if (pluginId) { this.pluginIdMap.delete(pluginId); } this.pluginVersionsMap.delete(name); }); } /** * get plugin by plugin name * will return the live versions * @param {string} type * @return {*} {PrePackage | undefined} */ async getPlugin(name) { return (await this.getPlugins([name]))[0]; } /** * get all libraries by plugin names * will return the live versions * @param {string[]} names * @return {*} {Promise<PrePackage[]>} */ async getPlugins(names) { const keys = names.map(name => { const liveVersion = this.getPluginLiveVersion(name); return this.generateKey(name, liveVersion || ''); }); return await this.find(keys); } async getPluginsById(ids) { const keys = ids .map(id => { const name = this.pluginIdMap.get(id); if (name) { const liveVersion = this.getPluginLiveVersion(name); return this.generateKey(name, liveVersion || ''); } }) .filter(foxpage_shared_1.isNotNill); return await this.find(keys); } /** * select one version * * @param {string} name plugin name * @return {*} */ getPluginLiveVersion(name) { var _a; return (_a = this.pluginVersionsMap.get(name)) === null || _a === void 0 ? void 0 : _a.liveVersion; } /** * update plugin live version * * @param {string} pkg plugin content */ updatePluginLiveVersion(pkg) { if (pkg.isLive) { const pkgInfo = this.pluginVersionsMap.get(pkg.name); if (pkgInfo) { pkgInfo.liveVersion = pkg.version; } } } /** * get plugin sync from hot * @param name plugin name * @param version plugin version * @returns pkg */ getPluginSync(name, version) { const versions = this.getPluginVersionsByNames([name])[name]; if (!versions) { return null; } if (version && versions.indexOf(version) === -1) { this.logger.warn(`get local plugin: ${name}@${version} is empty.`); return null; } // !version use live version, or use appoint version let curVersion = this.getPluginLiveVersion(name); if (version && version !== curVersion) { this.logger.info(`plugin ${name} local live version is: ${curVersion}, appoint version is: ${version}`); curVersion = version; } if (!curVersion) { this.logger.warn(`plugin ${name} version is invalid`); return null; } const key = this.generateKey(name, curVersion); const pkg = this.findOne(key); if (!pkg || pkg.version !== curVersion) { this.logger.warn(`get local plugin: ${key} is empty.`); return null; } // this.logger.info(`get local plugin: ${key} succeed.`); return pkg; } /** * get local plugin * * @param {string} name plugin name * @param {string} version plugin version * @return {*} {(PrePackage | null)} */ async getLocalPlugin(name, version) { const versions = this.getPluginVersionsByNames([name])[name]; if (!versions) { return null; } if (version && versions.indexOf(version) === -1) { this.logger.warn(`get local plugin: ${name}@${version} is empty.`); return null; } // !version use live version, or use appoint version let curVersion = this.getPluginLiveVersion(name); if (version && version !== curVersion) { this.logger.info(`plugin ${name} local live version is: ${curVersion}, appoint version is: ${version}`); curVersion = version; } if (!curVersion) { this.logger.warn(`plugin ${name} version is invalid`); return null; } const key = this.generateKey(name, curVersion); const pkg = await this.findOneFromLocal(key); if (!pkg || pkg.version !== curVersion) { this.logger.warn(`get local plugin: ${key} is empty.`); return null; } // this.logger.info(`get local plugin: ${key} succeed.`); return pkg; } /** * fetch libraries, instance libraries and install libraries then add to local * note: return contains plugin dependencies contents * @param {PackageFreshOption} [params] * @return {*} */ async freshPlugins(params) { const libraries = (params === null || params === void 0 ? void 0 : params.namedVersions) ? this.resolvePlugin(await this.fetchPluginsByNamedVersions(params.namedVersions)) : await this.fetchPlugins(params === null || params === void 0 ? void 0 : params.packageIds, { strategy: params === null || params === void 0 ? void 0 : params.strategy }); return await this.install(libraries, { cache: true }); } /** * install libraries * * @param {FPPackage[]} libraries * @param {{ cache: boolean; ignoreLocal:boolean }} [opt] {cache: will add libraries instance to manager} * @return {*} */ async install(libraries, opt) { const installs = await this.initInstalls(libraries, opt); return installs; } /** * fetch libraries from server * * @param {string[]} [pluginIds] * @return {*} */ async fetchPlugins(packageIds, opt = {}) { var _a; return await data_service_1.foxpageDataService.fetchPlugins(this.appId, Object.assign(Object.assign({ packageIds }, opt), { semver: (_a = this.config) === null || _a === void 0 ? void 0 : _a.version })); } /** * fetch libraries with name and version from server * * @param {PackageNamedVersion[]} nameVersions * @param {PackageFreshOption} opt {isCanary,...} * @return {Promise<FPPackageResponse[]>} */ async fetchPluginsByNamedVersions(nameVersions, opt) { var _a; return await data_service_1.foxpageDataService.fetchPluginsByNamedVersions(this.appId, { nameVersions, isCanary: opt === null || opt === void 0 ? void 0 : opt.isCanary, semver: (_a = this.config) === null || _a === void 0 ? void 0 : _a.version, }); } /** * listen the "ON_PULL" event * updates & removes is the plugin content id list * @protected * @param {ResourceUpdateInfo} data * @return {*} {Promise<void>} */ async onPull(data) { const { updates, removes } = data.plugin || {}; if (updates && updates.length > 0) { // this.markNeedUpdates(updates); await this.freshPlugins({ packageIds: updates }); } if (removes && removes.length > 0) { this.removePlugins(removes.map(item => this.pluginIdMap.get(item)).filter(foxpage_shared_1.isNotNill)); } } /** * on stash * @param data */ onStash(data) { var _a; (_a = data.plugins) === null || _a === void 0 ? void 0 : _a.map(item => { this.addPlugin(item); }); } /** * on fetch * list: the manager keys * @protected * @param {string[]} list * @return {*} {Promise<PackageImpl[]>} */ async onFetch(list) { return await this.freshPlugins({ namedVersions: list.map(item => { const [name, version] = this.splitKey(item); return { name, version }; }), }); } async createInstance(data) { const instance = this.newPlugin(data); return instance; } newPlugin(data) { return new plugin_1.PluginInstance(data, { appId: this.appId, appSlug: this.appSlug, resource: this.resourceConfig, logger: this.logger, }); } resolvePlugin(pluginInfos) { return pluginInfos.map(item => item.package); } /** * init need install libraries instances * * @private * @param {FPPackage[]} libraries * @param {{ cache: boolean, ignoreLocal:boolean }} [opt] * @return {*} */ async initInstalls(libraries, opt) { var _a; const installMap = new Map(); const { cache = false, ignoreLocal = false } = opt || {}; const create = async (list, { initDependencies } = { initDependencies: false }) => { for (const pkg of list) { const { name, version, components } = pkg; const key = this.generateKey(name, version); const localPkg = !ignoreLocal ? await this.getLocalPlugin(name, version) : null; // will install it if (!localPkg && !installMap.has(key)) { let newPkg; if (cache) { newPkg = await this.addPlugin(pkg); } else { newPkg = this.newPlugin(pkg); } if (newPkg) { installMap.set(key, newPkg); } } else { if (cache) { this.updatePluginLiveVersion(pkg); } } // init components // components: the dependencies contents if (initDependencies && (components === null || components === void 0 ? void 0 : components.length)) { await create(components); } } }; try { await create(libraries, { initDependencies: true }); } catch (e) { (_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(`install libraries failed: `, e); } return Array.from(installMap.values()); } /** * get plugin versions * * @private * @param {string[]} names plugin names * @return {*} {[key]: plugin name, [value]: versions} */ getPluginVersionsByNames(names) { const versionInfo = {}; names.forEach(name => { const { versions } = this.pluginVersionsMap.get(name) || {}; if (!versions) { // this.logger.warn(`not exist the plugin@${name} in pluginMap`); versionInfo[name] = null; } else { versionInfo[name] = versions; } }); return versionInfo; } updatePluginVersionsMap(pkg) { const { id, name, version } = pkg; const { versions } = this.pluginVersionsMap.get(name) || {}; if (versions) { versions.push(version); } else { this.pluginVersionsMap.set(name, { id, liveVersion: '', versions: [version] }); this.updatePluginLiveVersion(pkg); } } /** * destroy */ destroy() { super.destroy(); this.pluginIdMap.clear(); this.pluginVersionsMap.clear(); } } exports.CSRPluginManagerImpl = CSRPluginManagerImpl;