UNPKG

@micro-app/core

Version:

[Core] Pluggable micro application framework.

184 lines (148 loc) 5.52 kB
'use strict'; const { _, logger, moduleAlias, smartMerge } = require('@micro-app/shared-utils'); const PluginService = require('./libs/PluginService'); class Service extends PluginService { get __isMicroAppService() { return true; } __initInjectAliasModule__() { moduleAlias.addPath(this.nodeModulesPath); // 注入 custom node_modules const microsExtraConfig = this.microsExtraConfig; const microsConfig = this.microsConfig; // TODO 可优化, 则不需要走 alias, 直接 symlinks // 先判断是否存在 symlink, 如果存在则不需要走这个. const microsPaths = Object.values(microsConfig) .filter(item => item.hasSoftLink && microsExtraConfig[item.key] && !!microsExtraConfig[item.key].link) .map(item => item.nodeModulesPath) .sort(); moduleAlias.addPaths(microsPaths); } // 合并基本信息,以及 options 中的信息 _mergeConfig() { const selfConfig = this.selfConfig; const microsConfig = this.microsConfig; const finalConfig = smartMerge({}, ... Object.values(microsConfig).map(item => { if (!item) return {}; return _.pick(item, [ // 'alias', // 'aliasObj', 'resolveAlias', // 'shared', // 'sharedObj', 'resolveShared', 'options', ]); }), selfConfig.toJSON()); return Object.assign({}, finalConfig); } init(sync = false) { if (this.initialized) { return sync ? true : Promise.resolve(); } const fns = []; // fixed soft link - node_modules 不统一 fns.push(() => { this.__initInjectAliasModule__(); }); // init config,已提前,后面所有配置都在 this.config 上 fns.push(() => { this.config = this._mergeConfig(); // 注入全局的别名 moduleAlias.add(this.config.resolveShared); }); // preload fns.push(() => this._initPreloadPlugins()); fns.push(() => { if (sync) { return this._initPluginsSync(); } return this._initPlugins(); }); fns.push(() => { this.applyPluginHooks('onPluginInitWillDone'); this.initialized = true; // 再此之前可重新 init this.applyPluginHooks('onPluginInitDone'); }); // changeCommandOption fns.push(() => { const commandOptions = this.commandOptions || {}; Object.keys(commandOptions).forEach(name => { const command = this.commands[name]; if (!command) { logger.warn('[Plugin]', `changeCommandOption( ${name} ); ${name} not found`); return; } const newOpts = commandOptions[name]; let nV = newOpts; if (_.isFunction(nV)) { const oldOpts = command.opts; nV = newOpts(oldOpts); } if (nV && _.isPlainObject(nV)) { command.opts = nV; logger.debug('[Plugin]', `changeCommandOption( ${name} ); Success!`); return true; } }); }); fns.push(() => { return this.applyPluginHooks('onInitWillDone'); }); fns.push(() => { return this.applyPluginHooks('onInitDone'); }); fns.push(() => { logger.debug('[Plugin]', 'init(); Done!'); }); return sync ? fns.map(fn => fn()) : fns.reduce((chain, fn) => { return chain.then(() => fn()); }, Promise.resolve()); } initSync() { return this.init(true); } runCommand(rawName, rawArgs = {}) { rawArgs._ = Array.isArray(rawArgs._) && rawArgs._ || []; // fixed args logger.debug('[Plugin]', `raw command name: ${rawName}, args: `, rawArgs); // TODO 获取配置中的 options const commandOpts = this.extraConfig.command[rawName] || {}; if (_.isPlainObject(commandOpts)) { rawArgs = smartMerge({}, commandOpts, rawArgs); } const { name = rawName, args = rawArgs } = this.applyPluginHooks('modifyCommand', { name: rawName, args: rawArgs, }); logger.debug('[Plugin]', `run ${name} with args: `, args); const command = this.commands[name]; if (!command) { logger.throw('[core]', `Command "${name}" does not exists!`); } // 补充覆盖全局参数 for (const key of [ 'mode', 'target' ]) { if (args[key] == null) { args[key] = this[key]; } } // 清楚多余的命令 delete args.preRegisterPlugin; const { fn, opts } = command; // TODO 分发引用,待优化 this.applyPluginHooks('onRunCommand', { name, args, opts, }); return fn(args); } async run(name = 'help', args = { _: [] }) { await this.init(); return this.runCommand(name, args); } runSync(name = 'help', args = { _: [] }) { this.initSync(); return this.runCommand(name, args); } } module.exports = Service;