UNPKG

@foxpage/foxpage-node-sdk

Version:

foxpage node sdk

340 lines (339 loc) 12.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ComponentLoaderImpl = void 0; const lodash_1 = __importDefault(require("lodash")); const foxpage_manager_1 = require("@foxpage/foxpage-manager"); const foxpage_shared_1 = require("@foxpage/foxpage-shared"); const logger_1 = require("../logger"); /** * component loader * * @export * @class ComponentLoaderImpl * @implements {ComponentLoader} */ class ComponentLoaderImpl { constructor(appId, opt) { /** * the loaded components map * * @private` */ this.loadedMap = new Map(); /** * miss load componentMap * * @private */ this.missLoadMap = new Map(); /** * id -> version map * * @private */ this.resolvedVersionMap = new Map(); /** * all dependencies * "name":"version" list * @private * @type {string[]} */ this.dependencies = []; /** * dependencies loaded map * * @private */ this.loadedDependencyMap = new Map(); /** * dependencies miss load * key: "name":"version", value: {name, version} * @private * @type {FPPackageDependency[]} */ this.missLoadDependencyMap = new Map(); /** * for record the missed package version that had fetched from server * "name":"version" | "name":"" -> "name":"version", * @private */ this.missedVersionMap = new Map(); this.splitKey = (key) => { return foxpage_shared_1.packager.splitKey(key); }; this.app = (0, foxpage_manager_1.getApplication)(appId); this.opt = Object.assign({ autoDownloadComponent: true, useStructureVersion: false }, opt); this.logger = (0, logger_1.loggerCreate)('ComponentLoader'); } /** * load components * @param {StructureNode[]} schemas */ async load(schemas) { await this.resolveComponents(schemas); await this.resolveDependencies(); // auto download the missed packages if (this.opt.autoDownloadComponent) { const loadedMap = await this.downloadMisses(); await this.resolveMisses(loadedMap); } } /** * get loaded components * * @return {*} {Map<string, FoxpageComponent>} */ getLoadedComponents() { return this.loadedMap; } /** * get loaded dependencies * * @return {*} {Map<string, FoxpageComponent>} */ getLoadedDependencies() { return this.loadedDependencyMap; } /** * destroy: clear all source * */ async destroy() { this.loadedMap.clear(); this.missLoadMap.clear(); this.resolvedVersionMap.clear(); this.dependencies = []; this.loadedDependencyMap.clear(); this.missLoadDependencyMap.clear(); this.missedVersionMap.clear(); } /** * download the missed packages * * @private * @return {*} */ async downloadMisses() { var _a, _b; const loadedMap = new Map(); // get all messed packages name & versions const namedVersions = this.getMissedPackages(); if (namedVersions.length > 0) { this.logger.info('fetch missed packages from server'); this.logger.debug('fetch missed packages from server:', namedVersions); // fetch from server const fetches = await ((_a = this.app) === null || _a === void 0 ? void 0 : _a.packageManager.fetchPackagesByNamedVersions(namedVersions, { isCanary: this.opt.isCanary, isSemver: this.opt.isSemver, })); // get need install packages const packages = []; fetches === null || fetches === void 0 ? void 0 : fetches.forEach(item => { const key = this.generateKey(item.name, item.version); this.missedVersionMap.set(key, this.generateKey(item.package.name, item.package.version)); packages.push(item.package); }); // install // preview or canary will not cache the installed const cacheState = !this.opt.isPreviewMode && !this.opt.isCanary; const installed = await ((_b = this.app) === null || _b === void 0 ? void 0 : _b.packageManager.install(packages, { cache: cacheState, ignoreLocal: this.opt.isCanary, reInstall: this.opt.reLoadComponent, })); installed === null || installed === void 0 ? void 0 : installed.forEach(item => { loadedMap.set(this.generateKey(item.name, item.version), item); }); } return loadedMap; } /** * resolve the missed packages * * @private * @param {(Map<string, Package | null>)} loadedMap */ async resolveMisses(loadedMap) { const resolver = (list, cb) => { list.forEach(item => { const messages = new foxpage_shared_1.Messages(); const { name, version = '' } = item; const key = this.generateKey(name, version); const missKey = this.missedVersionMap.get(key); const pkg = missKey ? loadedMap.get(missKey) : null; let msg = ''; if (pkg) { msg = `package ${key} load succeed with version: ${pkg.version}`; // logger.info(msg); } else { msg = `package ${key} load failed`; // logger.warn(msg); } messages.push(msg); if (typeof cb === 'function') { cb(item, pkg, messages); } }); }; // resolve missed component resolver(Array.from(this.missLoadMap.values()), (item, pkg, messages) => { this.loadedMap.set(item.id, this.componentFormatter(item, pkg, messages)); }); // resolve missed dependencies resolver(Array.from(this.missLoadDependencyMap.values()), (item, pkg, messages) => { const key = this.generateKey(item.name, item.version); this.loadedDependencyMap.set(key, this.componentFormatter(this.generateStructureNode(key, item.name, item.version || ''), pkg, messages)); }); } /** * resolve the component * for divide the available or invalid * @private * @param {StructureNode[]} schemas */ async resolveComponents(schemas) { var _a, _b, _c; for (const item of schemas) { const { id, name, version = '', children } = item; // schema structure node const key = this.generateKey(name, version); if (this.isComponent(item) && !this.loadedMap.has(key)) { const messages = new foxpage_shared_1.Messages(); // in canary // will get all packages canary version from server // no canary will return last live version // reLoadComponent: need to load component all if (this.opt.isCanary || this.opt.reLoadComponent) { this.missLoadMap.set(id, item); this.setResolveVersion(item, item.version || ''); } else { // get component from local const pkg = await ((_a = this.app) === null || _a === void 0 ? void 0 : _a.packageManager.getLocalPackage(name, ((_b = this.opt) === null || _b === void 0 ? void 0 : _b.useStructureVersion) ? version : '')); if (pkg && pkg.available) { messages.push(`component@${item.id} -> package ${pkg.name} local version: ${pkg.version}`); // collect the dependencies (_c = pkg.dependencies) === null || _c === void 0 ? void 0 : _c.forEach(dep => { this.dependencies.push(this.generateKey(dep.name, dep.version)); }); this.loadedMap.set(id, this.componentFormatter(item, pkg, messages)); this.setResolveVersion(item, pkg.version); } else { this.logger.warn(`component@${item.id} -> package ${key} local not exist available version, try to download`); this.missLoadMap.set(id, item); this.setResolveVersion(item, item.version || ''); } } } if (children && children.length > 0) { await this.resolveComponents(children); } } } /** * resolve the dependencies * * @private */ async resolveDependencies() { var _a; for (const key of this.dependencies) { const [name, version = ''] = this.splitKey(key); const messages = new foxpage_shared_1.Messages(); const pkg = await ((_a = this.app) === null || _a === void 0 ? void 0 : _a.packageManager.getLocalPackage(name, version)); if (pkg && pkg.available) { messages.push(`dependency ${key} loaded`); this.loadedDependencyMap.set(key, this.componentFormatter(this.generateStructureNode(key, name, version), pkg, messages)); } else { this.logger.warn(`dependency ${key} loaded failed, try to auto download.`); this.missLoadDependencyMap.set(key, { name, version }); } } } /** * get the missed packages * * @private * @return {PackageNamedVersion} namedVersions */ getMissedPackages() { const missComponents = Array.from(this.missLoadMap.values()); let missList = []; missComponents.forEach(item => { const versions = this.resolvedVersionMap.get(item.id) || []; versions.forEach(version => { missList.push({ name: item.name, version, }); }); }); missList = missList.concat(Array.from(this.missLoadDependencyMap.values())); const namedVersions = lodash_1.default.uniqWith(missList, lodash_1.default.isEqual); return namedVersions; } componentFormatter(node, pkg, messages) { const newMsg = messages || new foxpage_shared_1.Messages(); if (pkg) { const { type, version, source, supportNode, deps, url, downloadUrl, debugUrl, cssUrl, componentFactory, messages: pkgMessages, } = pkg; pkgMessages.forEach(msg => { newMsg.push(msg); }); let meta = pkg.meta; // will remove if (!meta) { meta = {}; } if (cssUrl) { meta.assets = [{ url: cssUrl, type: 'css' }]; } return { type, name: node.name, version: node.version || version, isLive: pkg.isLive, browserURL: url, debugURL: debugUrl || url, nodeURL: downloadUrl, cssURL: cssUrl, supportSSR: supportNode, factory: componentFactory, dependencies: deps, source, meta, messages, }; } return { name: node.name, version: node.version, messages: newMsg.hasError ? newMsg : undefined, }; } generateStructureNode(key, name, version) { return { id: `builtin_${key}`, name, version, props: {}, type: 'react.component' }; } setResolveVersion(structureNode, version) { const nodeId = structureNode.id; if (!this.resolvedVersionMap.has(nodeId)) { this.resolvedVersionMap.set(nodeId, []); } const list = this.resolvedVersionMap.get(nodeId) || []; if (list.indexOf(version) === -1) { list.push(version); } this.resolvedVersionMap.set(nodeId, list); } isComponent(structureNode) { return !!structureNode.name; } generateKey(name, version) { return foxpage_shared_1.packager.generateKey(name, version); } } exports.ComponentLoaderImpl = ComponentLoaderImpl;