@micro-app/core
Version:
[Core] Pluggable micro application framework.
375 lines (330 loc) • 11.5 kB
JavaScript
'use strict';
const { _, loadFile, logger, stringifyObject, path, pluginResolution } = require('@micro-app/shared-utils');
const CONSTANTS = require('../../Constants');
const validateSchema = require('../../../utils/validateSchema');
const parsePlugin = require('../../../utils/parsePlugin');
const SCHEMA = require('./configSchema');
const INIT = Symbol('@BaseConfig#INIT');
const KEY_ORIGNAL_CONFIG = Symbol('@BaseConfig#KEY_ORIGNAL_CONFIG');
const KEY_PACKAGE = Symbol('@BaseConfig#KEY_PACKAGE');
const KEY_PACKAGE_PATH = Symbol('@BaseConfig#KEY_PACKAGE_PATH');
const OPTION_ROOT = Symbol('@MicroAppConfig#ROOT');
const OPTION_FILEPATH = Symbol('@MicroAppConfig#FILEPATH');
const OPTION_FILENAME = Symbol('@MicroAppConfig#FILENAME');
const OPTION_DIRNAME = Symbol('@MicroAppConfig#DIRNAME');
const OPTION_ORIGINAL_ROOT = Symbol('@MicroAppConfig#ORIGINAL_ROOT');
const OPTION_LOAD_SUCCESS = Symbol('@MicroAppConfig#LOAD_SUCCESS');
const OPTION_TYPE = Symbol('@MicroAppConfig#TYPE');
class BaseConfig {
/**
* Creates an instance of BaseConfig.
* @param {DEFAULT_CONFIG} config config
* @param {Object} opts opts
* @memberof BaseConfig
*/
constructor(config, opts = {}) {
this[OPTION_FILEPATH] = opts.filePath;
this[OPTION_ORIGINAL_ROOT] = opts.originalRoot;
// 以上必须有
this[OPTION_ROOT] = opts.root || path.dirname(opts.filePath);
this[OPTION_FILENAME] = opts.filename || path.basename(opts.filePath);
this[OPTION_DIRNAME] = opts.dirname || path.basename(this.root);
this[OPTION_LOAD_SUCCESS] = opts.loadSuccess || false;
this[OPTION_TYPE] = opts.type || 'slave';
// 校验 config
this.validate(config);
this[KEY_ORIGNAL_CONFIG] = config;
this[INIT]();
}
validate(config) {
return validateSchema(SCHEMA, config);
}
[INIT]() {
if (!this[OPTION_LOAD_SUCCESS]) {
// 配置文件未加载成功.
// ZAP 优化提示
logger.throw('[core]', '[LOAD_FAIL]', `You should be create "${CONSTANTS.CONFIG_NAME}.js" in "${this.root}"`);
}
if (this.root) {
try {
this[KEY_PACKAGE_PATH] = path.resolve(this.root, CONSTANTS.PACKAGE_JSON);
this[KEY_PACKAGE] = loadFile(this.root, CONSTANTS.PACKAGE_JSON);
} catch (error) {
this[KEY_PACKAGE_PATH] = '';
this[KEY_PACKAGE] = {};
logger.warn('[core]', `Not Fount "${CONSTANTS.PACKAGE_JSON}" !`);
}
}
}
get filename() {
return this[OPTION_FILENAME] || '';
}
get dirname() {
return this[OPTION_DIRNAME] || '';
}
get config() {
return this[KEY_ORIGNAL_CONFIG] || {};
}
get originalConfig() {
return this.config;
}
get root() {
return this[OPTION_ROOT] || '';
}
get originalRoot() {
return this[OPTION_ORIGINAL_ROOT] || this.root || '';
}
get hasSoftLink() {
return this.root !== this.originalRoot;
}
get filePath() {
return this[OPTION_FILEPATH] || '';
}
get nodeModulesPath() {
if (this.root) {
const nodeModules = CONSTANTS.NODE_MODULES_NAME || 'node_modules';
return path.join(this.root, nodeModules);
}
return '';
}
get strict() {
return this.config.strict !== false;
}
get packagePath() {
return this[KEY_PACKAGE_PATH] || '';
}
get package() {
return _.cloneDeep(this[KEY_PACKAGE] || {});
}
// 唯一标识
get key() {
return this.packageName || path.basename(path.dirname(this.root)) || '';
}
get name() {
const config = this.config;
return config.name || this.packageName || '';
}
get packageName() {
return this.package.name || '';
}
get namespace() {
const config = this.config;
return config.namespace || '';
}
get aliasName() {
let aliasName = this.namespace;
if (!aliasName) {
aliasName = this.name || 'alias';
if (!aliasName.startsWith(CONSTANTS.SCOPE_NAME)) { // 加入作用域,并去除原 scope 的 @ 开头符
aliasName = `${CONSTANTS.SCOPE_NAME}/${aliasName.replace(/^@/ig, '')}`;
}
}
return aliasName.startsWith('@') ? aliasName : `@${aliasName}`;
}
get version() {
const config = this.config;
return config.version || this.package.version || '';
}
get description() {
const config = this.config;
return config.description || this.package.description || '';
}
get type() {
return this[OPTION_TYPE] || 'slave'; // master/slave
}
get isMaster() {
return this.type === 'master';
}
get packages() {
const config = this.config;
const _micros = config.micros;
if (_micros && Array.isArray(_micros)) {
return [ ...new Set(_micros) ].map(item => {
if (_.isString(item)) {
return {
name: item,
spec: false,
};
}
return item;
});
} else if (_micros && _.isPlainObject(_micros)) {
return Object.keys(_micros).map(key => {
const pkg = _micros[key];
if (_.isString(pkg)) {
return {
name: key,
spec: pkg,
};
}
return {
name: key,
...pkg,
};
});
}
return [];
}
get micros() {
const packages = this.packages;
if (packages && Array.isArray(packages)) {
return [ ...new Set(packages.map(item => item.name).filter(name => !!name)) ];
}
return [];
}
// 后端共享
get sharedObj() {
const config = this.config;
const currShared = config.shared || config.share;
if (currShared) { // 兼容旧版
return Object.keys(currShared).reduce((obj, key) => {
const aliasObj = currShared[key];
if (aliasObj && _.isString(aliasObj)) {
obj[key] = {
link: aliasObj,
};
} else if (aliasObj && _.isPlainObject(aliasObj)) {
const link = aliasObj.link;
if (link && _.isString(link)) {
obj[key] = aliasObj;
}
}
return obj;
}, {});
}
const currAlias = config.alias || {};
return Object.keys(currAlias).reduce((obj, key) => {
const aliasObj = currAlias[key];
if (aliasObj && _.isString(aliasObj)) {
obj[key] = {
link: aliasObj,
};
} else if (aliasObj && _.isPlainObject(aliasObj)) {
const link = aliasObj.link;
if (link && _.isString(link)) {
obj[key] = aliasObj;
}
}
return obj;
}, {});
}
// 后端共享
get shared() {
const currAlias = this.sharedObj || {};
return Object.keys(currAlias).reduce((obj, key) => {
const aliasObj = currAlias[key];
obj[key] = aliasObj.link;
return obj;
}, {});
}
get resolveShared() {
const alias = {};
const aliasName = this.aliasName;
if (aliasName) {
const currShared = this.shared;
Object.keys(currShared).forEach(k => {
const p = currShared[k];
const aliasKey = `${aliasName}/${k}`;
if (!alias[aliasKey] && _.isString(p)) {
const filePath = path.resolve(this.root, p);
alias[aliasKey] = filePath;
}
});
}
return alias;
}
// 前端共享
get aliasObj() {
const config = this.config;
const currAlias = config.alias || {};
return Object.keys(currAlias).reduce((obj, key) => {
const aliasObj = currAlias[key];
if (aliasObj && _.isString(aliasObj)) {
obj[key] = {
link: aliasObj,
};
} else if (aliasObj && _.isPlainObject(aliasObj)) {
if (aliasObj.server === true || _.isString(aliasObj.type) && aliasObj.type.toUpperCase() === 'SERVER') {
// server ?
return obj;
}
const link = aliasObj.link;
if (link && _.isString(link)) {
obj[key] = aliasObj;
}
}
return obj;
}, {});
}
get alias() {
const currAlias = this.aliasObj || {};
return Object.keys(currAlias).reduce((obj, key) => {
const aliasObj = currAlias[key];
obj[key] = aliasObj.link;
return obj;
}, {});
}
get resolveAlias() {
const alias = {};
const aliasName = this.aliasName;
if (aliasName) {
const currAlias = this.alias;
Object.keys(currAlias).forEach(key => {
const p = currAlias[key];
const aliasKey = `${aliasName}/${key}`;
if (!alias[aliasKey] && _.isString(p)) {
const filePath = path.resolve(this.root, p);
alias[aliasKey] = filePath;
}
});
}
return alias;
}
get plugins() {
const config = this.config;
let _plugins = config.plugins || [];
// 支持自动加载 pkg.dependencies 中的插件
// 如果 type = master 则同时加载 devDependencies 中的插件
if (_plugins === true) {
const pkg = this.package || {};
const deps = Object.assign({},
(this.isMaster ? pkg.devDependencies : {}) || {},
pkg.devDependencies || {});
_plugins = Object.keys(deps).filter(pluginResolution.isPlugin);
}
return _plugins.map(item => parsePlugin(item));
}
// 这是一个参与合并,不进行校验的对象(提供参数扩展使用)
get options() {
return this.config.options || {};
}
toJSON() {
return {
key: this.key,
name: this.name,
packageName: this.packageName,
aliasName: this.aliasName,
version: this.version,
type: this.type,
description: this.description,
root: this.root,
originalRoot: this.originalRoot,
hasSoftLink: this.hasSoftLink,
nodeModulesPath: this.nodeModulesPath,
strict: this.strict,
filePath: this.filePath,
micros: this.micros,
packagePath: this.packagePath,
// package: this.package,
// options: this.options,
};
}
toString() {
const config = this.toJSON();
return stringifyObject(config, {
indent: ' ',
singleQuotes: false,
});
}
}
module.exports = BaseConfig;