@micro-app/core
Version:
[Core] Pluggable micro application framework.
238 lines (203 loc) • 5.99 kB
JavaScript
'use strict';
const os = require('os');
const { logger, _, semverRegex, debug, yParser, smartMerge } = require('@micro-app/shared-utils');
const path = require('path');
const CONSTANTS = require('../../Constants');
const MicroAppConfig = require('../../MicroAppConfig');
const INIT_DEFAULT_ENV = Symbol('INIT_DEFAULT_ENV');
const INIT_ENV = Symbol('INIT_ENV');
class BaseService {
constructor(context) {
this.initialized = false; // 是否已经初始化
this.context = getContext(context); // 优先使用 context 下配置
this.config = {};
// 初始化
this[INIT_ENV]();
this[INIT_DEFAULT_ENV]();
// reset logger level
if (process.env.MICRO_APP_LOGGER_LEVEL) {
logger.level = process.env.MICRO_APP_LOGGER_LEVEL;
}
}
get debug() {
const _debug = debug('microapp:core');
Object.defineProperty(this, 'debug', { value: _debug });
return _debug;
}
/**
* @private
*
* @memberof BaseService
*/
[INIT_ENV]() { // 支持对模式解析
const dotenv = require('dotenv');
const dotenvExpand = require('dotenv-expand');
const load = envFileName => {
const envPath = path.resolve(this.root, envFileName);
const result = dotenv.config({ path: envPath });
if (result.error) {
// only ignore error if file is not found
if (result.error.toString().indexOf('ENOENT') < 0) {
logger.error(result.error);
}
} else {
dotenvExpand(result);
if (result.parsed) {
const config = result.parsed;
if (config.HOSTNAME) { // fixed
process.env.HOSTNAME = config.HOSTNAME;
}
}
}
};
load('.env');
load('.env.local');
// default env
const mode = this.mode;
if (mode) {
// 全局环境模式 production, development
process.env.NODE_ENV = mode;
}
if (mode) {
load(`.env.${mode}`);
load(`.env.${mode}.local`);
}
logger.debug('[dotenv]', `dotenv parsed envs:${os.EOL}`, JSON.stringify(this.env, null, 4));
}
/**
* 注入默认环境变量
* @private
*
* @memberof BaseService
*/
[INIT_DEFAULT_ENV]() {
const env = {
VERSION: {
force: true,
value: semverRegex().exec(this.version)[0],
},
};
if (this.mode === 'test') {
env.TEST = {
value: true,
};
}
Object.keys(env).forEach(key => {
const _k = `${CONSTANTS.ENV_PREFIX}${key.toUpperCase()}`;
const item = env[key];
if (item.force || _.isUndefined(process.env[_k])) {
process.env[_k] = item.value;
}
});
}
get env() { // 引用:环境变量
return process.env;
}
get root() {
// const ctxRoot = this.context.root; // 从参数中获取
return CONSTANTS.ROOT;
}
get version() {
return CONSTANTS.VERSION;
}
get mode() {
const ctxMode = this.context.mode; // 从参数中获取
return ctxMode || process.env.NODE_ENV || 'development'; // "production" | "development"
}
get target() {
const ctxTarget = this.context.target; // 从参数中获取
return ctxTarget || process.env.MICRO_APP_TARGET || 'app'; // "app" | "web" | "lib"
}
get isDev() {
return this.mode === 'development';
}
/**
* self
* @return {MicroAppConfig} self
* @readonly
* @memberof BaseService
* @private
*/
get self() {
// 加载自己
const _self = MicroAppConfig.createInstance(this.root, { type: 'master' });
if (!_self) {
logger.throw('[core]', 'Not Found Config!!!'); // 一般不会出现
}
// redefine getter to lazy-loaded value
Object.defineProperty(this, 'self', {
value: _self,
});
return _self;
}
/**
* self alias
* @return {MicroAppConfig} clone self
* @readonly
* @memberof BaseService
*/
get selfConfig() {
return _.cloneDeep(this.self) || {};
}
get type() {
return this.selfConfig.type || '';
}
get pkg() {
return this.selfConfig.package || {};
}
get strictMode() {
return this.selfConfig.strict;
}
get selfKey() {
return this.selfConfig.key || this.pkg.name;
}
get nodeModulesPath() {
return this.selfConfig.nodeModulesPath;
}
get micros() {
return this.selfConfig.micros;
}
/**
* @private
* @param {string} name key
* @return {boolean} true - exist key
*/
hasKey(name) {
return !!this[name];
}
/**
* 扩充合并 context
* @param {Array|String} ctx 上下文
* @return {Object} context
*/
mergeContext(ctx = []) {
const args = [].concat(ctx);
const newCtx = yParser(args);
return smartMerge(this.context, newCtx);
}
}
module.exports = BaseService;
/**
* fixed args
* @param {Object} context args
* @return {Object} right context
*/
function getContext(context = {}) {
if (!_.isPlainObject(context)) {
context = {};
}
if (!Array.isArray(context._)) {
context._ = [];
}
context = _.cloneDeep(context);
if (process.env.MICRO_APP_CONTEXT) {
const _ctx = process.env.MICRO_APP_CONTEXT.split(','); // 环境变量中的上下文,分割
try {
const args = yParser(_ctx);
smartMerge(context, args);
} catch (e) {
// nothing...
}
}
return context;
}