UNPKG

@foxpage/foxpage-manager

Version:

foxpage resource manager

193 lines (192 loc) 8.26 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PackageInstance = void 0; const fs_extra_1 = require("fs-extra"); const lodash_1 = __importDefault(require("lodash")); const foxpage_shared_1 = require("@foxpage/foxpage-shared"); const cache_1 = require("../cache"); const reporter_1 = require("../reporter"); const fetcher_1 = require("./fetcher"); const resolver_1 = require("./resolver"); const utils_1 = require("./utils"); const wrapper_1 = require("./wrapper"); /** * package * * @export * @interface Package */ class PackageInstance extends foxpage_shared_1.PrePackageInstance { constructor(info, opt) { super(info, opt); this._loaded = false; this.status = 'preInstall'; this.available = false; this.filePath = this.name ? (0, resolver_1.resolvePackageJSPath)(this.appId, this.name, this.version) : ''; this.reporter = (0, reporter_1.getReporter)(); } get exported() { var _a, _b, _c, _d, _e; if (!this.supportNode || !this.filePath) { (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`package ${this.name}@${this.version} not support node or not exist the file path`); return undefined; } // load file // ssrSupport === false, not need load file if (!this._loaded && (((_b = this.meta) === null || _b === void 0 ? void 0 : _b.ssrSupport) === undefined || ((_c = this.meta) === null || _c === void 0 ? void 0 : _c.ssrSupport) === true)) { try { const res = (0, utils_1.loadFile)(this.filePath); if (!(res.default && (typeof res.default === 'function' || !lodash_1.default.isEmpty(res.default)))) { (_d = this.logger) === null || _d === void 0 ? void 0 : _d.error(`package ${this.name}@${this.version} load file is empty or invalid: not a function`); this.available = false; this.status = 'loadFailed'; return; } this._exported = res; this._loaded = true; } catch (error) { this.messages.push(error); (_e = this.logger) === null || _e === void 0 ? void 0 : _e.error(`package ${this.name}@${this.version} get exported failed:`, error); this.available = false; this.status = 'loadFailed'; return; } } return this._exported; } get componentFactory() { return (0, foxpage_shared_1.getESModuleExport)(this.exported).default; } /** * install package * * @param {PackageInstallOption} opt */ async install(opt = {}) { var _a, _b, _c, _d, _e; this.status = 'installing'; // ssrSupport === false or other values, not need fetch code if (!(((_a = this.meta) === null || _a === void 0 ? void 0 : _a.ssrSupport) === undefined || ((_b = this.meta) === null || _b === void 0 ? void 0 : _b.ssrSupport) === true)) { this.available = true; this.status = 'installed'; } else { try { const cost = (_c = this.reporter) === null || _c === void 0 ? void 0 : _c.cost(this.name); await this.fetchCode(opt); this.available = true; this.status = 'installed'; const loadCost = cost === null || cost === void 0 ? void 0 : cost(); (_d = this.reporter) === null || _d === void 0 ? void 0 : _d.componentReporter(this.name, { version: this.version, loadCost }, { appId: this.appId }); } catch (error) { this.available = false; this.status = 'fail'; this.messages.push(error); (_e = this.logger) === null || _e === void 0 ? void 0 : _e.error(`install package ${this.name}@${this.version}@${this.downloadUrl} failed:`, error); return; } } } async fetchCode({ inspect = false, wrap = true }) { var _a, _b; if (this.available && this.filePath && (await (0, fs_extra_1.pathExists)(this.filePath))) { (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`package ${this.name}@${this.version} path ${this.filePath} exist.`); return; } if (!this.source || !this.source.node) { return foxpage_shared_1.optional.fail('miss source'); } let fetchResult = await this.fetch(this.downloadUrl, this.downloadProxy); if (fetchResult.fail) { (_b = this.logger) === null || _b === void 0 ? void 0 : _b.error(`fetch package ${this.name}@${this.version} failed: ${this.downloadUrl}`); // with retry downloads if (this.retryDownloads && this.retryDownloads.length > 0) { fetchResult = await this.retry(this.retryDownloads); if (fetchResult.fail) { throw fetchResult.error; } } else { throw fetchResult.error; } } const code = wrap && this.deps.length > 0 ? (0, wrapper_1.wrapCode)(fetchResult.data.content, this) : fetchResult.data.content; if (inspect) { const inspectResult = await this.inspectPackage(code); if (inspectResult.fail) { const msg = `${this.name}@${this.version} inspect fail: ${inspectResult.error.message}`; this.supportNode = false; throw new Error(msg); } } await this.processJSCode(code); } async inspectPackage(code) { try { (0, utils_1.runInNodeContext)(code); return foxpage_shared_1.optional.ok(true); } catch (error) { return foxpage_shared_1.optional.fail(error); } } async fetch(downloadUrl, proxy) { if (!downloadUrl) { return foxpage_shared_1.optional.fail('miss downloadUrl'); } const _opt = {}; if (proxy && proxy.host && proxy.protocol) { _opt.proxy = proxy; } const fetcher = new fetcher_1.PackageFetcher(downloadUrl, { downloadTimeout: 3000, requestOpt: _opt, }); const result = await fetcher.fetch(); return result; } async retry(list) { var _a, _b; let result = {}; for (const item of list) { result = await this.fetch(item.url, item.proxy); if (result.ok) { (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`retry fetch package ${this.name}@${this.version} succeed: ${item.url}`); break; } else { (_b = this.logger) === null || _b === void 0 ? void 0 : _b.error(`retry fetch package ${this.name}@${this.version} failed: ${item.url}`); } } return result; } async processJSCode(jsContent) { try { const targetJsPath = (0, resolver_1.resolvePackageJSPath)(this.appId, this.name, this.version); const lockedStr = targetJsPath.replace('.js', '-locked'); const exist = await (0, fs_extra_1.pathExists)(targetJsPath); if (!(exist && this.available)) { await cache_1.locker.withLock(lockedStr, async () => { var _a; await (0, fs_extra_1.outputFile)(targetJsPath, jsContent, { encoding: 'utf-8', flag: 'w', }); (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info('install package %s@%j succeed', this.name, this.version); }); } } catch (err) { const isExistError = err.code === 'EEXIST' || String(err).includes('exists'); if (!isExistError) { throw err; } } } } exports.PackageInstance = PackageInstance;