项目配置
编写
hzero-front 使用生成的方式编写 utils/config.js 文件
配置说明
配置是固定字符串
高级配置
route
:init
返回的值 可以 被routeMap
这个环境变量中对应值覆盖noChange
: 不能在运行中被changeRoute
更改deps
&get
: 该配置依赖于其他配置deps
, 生成方法是get
config/apiConfig.js 文件的编写
固定配置
const config ={
VERSION: 'v1',
};
后端服务路由
const config ={
HZERO_HXXX: {
init: () => {
return "'/hxxx'";
},
route: true,
},
};
不可在运行时更改
const config = {
CLIENT_ID: {
init: () => {
return '`${process.env.CLIENT_ID}`';
},
noChange: true,
},
};
依赖其他变量
const config = {
AUTH_LOGOUT_URL: {
deps: ['AUTH_HOST'],
get: (AUTH_HOST) => {
return `${AUTH_HOST}/logout`;
},
},
};
实际文件
- 除了 scripts/genConfig.js 外 其他文件都略有删减
- 其他项目如果也需要使用 apiConfig, 需要将 scripts/genConfig.js中的 changeRoute 方法 改名为 {projectName}ChangeRoute
config/apiConfig.js 编写文件
/**
* 配置 utils/config 下的常量
*/
/**
* deps 和 get 必须同时出现
* get 和 init 是互斥的
* 如果有 route, 那么必须有init
*
* @typedef {Object|string} CONFIG
* @property {?Function} init - 返回返回字符串包裹的字符串模板; 参照 CLIENT_ID
* @property {?boolean} noChange - 是否能改变 false/undefined => 能改变, true => 不能改变; 参照 CLIENT_ID
* @property {?boolean} route - 是否能被环境变量routeMap改变 false/undefined => 可以改变, true => 不能改变; 参照 HZERO_PLATFORM
* @property {?string[]} deps - 依赖的CONFIG, 当 依赖的CONFIG 改变时 会同时改变; 参照 AUTH_SELF_URL 的配置
* @property {?Function} get - 依赖改变生成自己的方法; (...deps: string[]) => string; 参照 AUTH_SELF_URL 的配置
*/
/**
* @type {{[configId]: CONFIG}}
*/
const config = {
CLIENT_ID: {
init: () => {
return '`${process.env.CLIENT_ID}`';
},
noChange: true,
},
WEBSOCKET_URL: {
init: () => {
return '`${process.env.WEBSOCKET_HOST}`';
},
},
HZERO_PLATFORM: {
init: () => {
return "'/hpfm'";
},
route: true,
},
HZERO_FILE: {
deps: ['API_HOST', 'HZERO_HFLE'],
get: (API_HOST, HZERO_HFLE) => {
return `${API_HOST}${HZERO_HFLE}`;
},
},
VERSION_IS_OP: {
deps: ['PLATFORM_VERSION'],
get: (PLATFORM_VERSION) => {
return `${PLATFORM_VERSION}` === 'OP'; // OP版
},
init: () => {
return '`${process.env.PLATFORM_VERSION}` === \'OP\''; // OP版
},
},
// ...
};
const prefix = `/**
* 不要直接修改这个文件, 请修改 config/apiConfig 文件
* Config - 全局统一配置
* @date: 2018-6-20
* @author: niujiaqing <njq.niu@hand-china.com>
* @version: 0.0.1
* @copyright Copyright (c) 2018, Hand
*/
`;
const suffix = '';
module.exports = {
config,
prefix,
suffix,
};
生成方法文件 scripts/genConfig.js
/**
* TODO: 已经可以直接通过 changeRoute('/iam', '/iam-xxxxx') 来在运行时改变配置了, 需要将 .route 相关的代码注释取消 和注释之下的代码, 需要注意单引号问题, 已知问题, 不能有重复的 配置名
* 通过 ../config/apiConfig 生成 utils/config 文件
* @author WY <yang.wang06@hand-china.com>
* @date 2019-05-22
* @copyright ® HAND
*/
const {config, prefix, suffix} = require('../config/apiConfig');
const helpFuncMap = {};
const initLang = [];
const changeRouteSwitch = new Map(); // 存储 case 代码
const configChangeFunc = [];
const exportConfig = [];
// 不需要从 'HZERO_PLATFORM' -> '/hpfm' 的映射
// '/hpfm' -> 'HZERO_PLATFORM' 的映射
// const routeMapVar = {};
Object.entries(config).forEach(([key, value]) => {
// #region exportConfig
exportConfig.push(key);
// #endregion
// #region initConfig
let varType = 'let';
if (value.noChange) {
varType = 'const';
}
// init lang
if (value.init) {
if (value.route) {
// 路由 不能直接被环境变量更改, 所有 route: true 的 init 是直接返回可用的变量
const routePath = value.init();
// if (routeMapVar[routePath]) {
// throw new Error(formatString('route define has two config %12s, %12s has same value %8s', routeMapVar[routePath], key, routePath));
// } else {
// routeMapVar[routePath] = key;
// }
initLang.push(formatString('%8s %16s = %s;', varType, key, ` routeMap[${routePath}] || ${routePath}`));
} else {
// not route
initLang.push(formatString('%8s %16s = %s;', varType, key, value.init()));
}
} else if (value.get) {
// get config return body;
// TODO: 初始化时也调用方法
// const retBody = value.get.toString().match(/return ([\S\s]+);/);
// initLang.push(`${varType} ${key} = ${(retBody && retBody[1] || '')};`);
initLang.push(formatString('%8s %16s = %s;', varType, key, `change${key}(${value.deps.join(', ')})`));
} else {
initLang.push(formatString('%8s %16s = %s;', varType, key, `'${value}'`));
}
// #endregion
if (value.noChange) {
// noChange 不能在运行时更改
return;
}
// #region help func
// const helpKey = value.route ? value.init() : key;
const helpKey = key;
const curHelp = helpFuncMap[helpKey] || {changeConfig: [], depBy: []};
helpFuncMap[helpKey] = curHelp;
if (value.deps) {
value.deps.forEach((depKey) => {
// const depHelpKey = (config[depKey] && config[depKey].route) ? config[depKey].init() : depKey;
const depHelpKey = depKey;
const depHelp = helpFuncMap[depHelpKey] || {changeConfig: [], depBy: []};
helpFuncMap[depHelpKey] = depHelp;
depHelp.changeConfig.push(helpKey);
curHelp.depBy.push(helpKey);
});
}
curHelp.changeConfig.push(helpKey);
// #endregion
// #region change route func
// const caseKey = value.route ? value.init() : key;
const caseKey = key;
const curCase = changeRouteSwitch.get(caseKey) || [];
changeRouteSwitch.set(caseKey, curCase);
if (value.deps) {
// if have deps, must have get
value.deps.forEach((depKey, depIndex) => {
const depCase = changeRouteSwitch.get(depKey) || [];
changeRouteSwitch.set(depKey, depCase);
const newDep = [...value.deps];
newDep[depIndex] = 'value';
depCase.push(`${key} = change${key}(${newDep.join(', ')});`);
});
const changeFuncLines = value.get.toString().split('\n');
changeFuncLines[0] = `function change${key} (${value.deps.join(', ')}) {`;
const lastLineNo = changeFuncLines.length - 1;
configChangeFunc.push(
changeFuncLines.map((line, lineNo) => {
if (lineNo === 0 || lineNo === lastLineNo) {
return line.trim();
} else {
return ` ${line.trim()}`;
}
}).join('\n'));
}
// every config can change it self
curCase.push(`${key} = value;`);
// #endregion
});
function renderChangeRouteSwitch() {
const strs = [
'window.changeRoute = function changeRoute(key, value) {',
' if(key && value) {',
' switch(key) {',
];
for ([key, value] of changeRouteSwitch.entries()) {
if (value.noChange) {
return;
}
const curCase = (value || []);
strs.push(` case '${key}':`,
curCase.map(str => {
return ` ${str}`;
}).join('\n'),
' break;',
);
}
strs.push(' default:');
strs.push(' console.error(`${key} is not exists`);');
strs.push(' helpMethod();');
strs.push(' break;');
strs.push('',
' }',
' } else {',
' helpMethod(key);',
' }',
'};',
);
return strs.join('\n');
}
function renderHelpMethod() {
const strs = [];
strs.push(`const helpMethodAssist = ${JSON.stringify(helpFuncMap)};`,
'function helpMethod(key) {',
' if(key && helpMethodAssist[key]) {',
` console.error(\`\${key} 会更改: [\${helpMethodAssist[key].changeConfig.join(', ')}], 被级连更改: [\${helpMethodAssist[key].depBy.join(', ')}]\`)`,
' } else {',
` console.error('使用 changeRoute() 查看可以更改的参数');`,
` console.error('使用 changeRoute("参数") 查看具体改变');`,
` console.error('使用 changeRoute("参数", "参数值") 更改参数');`,
` console.error(\`可以更改的配置: [\${Object.keys(helpMethodAssist).join(', ')}]\`);`,
' }',
'}');
return strs.join('\n');
}
function renderExportsConfig() {
return ['export {', exportConfig.join(',\n '), '};'].join('\n');
}
const configData = [
'/* eslint-disable no-shadow,camelcase,import/no-mutable-exports,no-console */',
'// TODO: 自动生成的 src/utils/config 禁用了部分 eslint, 请查看 scripts/genConfig.js',
prefix,
'const routeMap = JSON.parse(process.env.routeMap || \'{}\');',
// `const routeMapVar = ${JSON.stringify(routeMapVar)};`,
'// #region initConfig',
initLang.join('\n'),
'// #endregion',
'',
'// #region changeConfig Funcs',
configChangeFunc.join('\n'),
'// #endregion',
'',
'// #region changeRoute',
renderChangeRouteSwitch(),
'// #endregion',
'',
'// #region helpMethod',
renderHelpMethod(),
'// #endregion',
'',
'// #regioin exportsConfig',
renderExportsConfig(),
'// #endregion',
suffix,
];
require('fs').writeFileSync(
require('path').resolve(__dirname, '../src/utils/config.js'),
configData.join('\n'),
);
function formatString(format, ...args) {
let argIndex = 0;
return format.replace(/%(\d*)s/g, (testStr, match/* , start, all */) => {
const padNum = +match;
let ret;
if (!padNum) {
ret = args[argIndex]
} else {
ret = ("" + args[argIndex]).padEnd(padNum, ' ');
}
argIndex++;
return ret;
});
}
生成的 src/config.js 文件
/* eslint-disable no-shadow,camelcase,import/no-mutable-exports,no-console */
// TODO: 自动生成的 src/utils/config 禁用了部分 eslint, 请查看 scripts/genConfig.js
/**
* 不要直接修改这个文件, 请修改 config/apiConfig 文件
* Config - 全局统一配置
* @date: 2018-6-20
* @author: niujiaqing <njq.niu@hand-china.com>
* @version: 0.0.1
* @copyright Copyright (c) 2018, Hand
*/
const routeMap = JSON.parse(process.env.routeMap || '{}');
// #region initConfig
const CLIENT_ID = `${process.env.CLIENT_ID}`;
let WEBSOCKET_URL = `${process.env.WEBSOCKET_HOST}`;
let HZERO_PLATFORM = routeMap['/hpfm'] || '/hpfm';
let HZERO_HFLE = routeMap['/hfle'] || '/hfle';
let HZERO_FILE = changeHZERO_FILE(API_HOST, HZERO_HFLE);
let VERSION_IS_OP = `${process.env.PLATFORM_VERSION}` === 'OP';
// #endregion
// #region changeConfig Funcs
function changeHZERO_FILE(API_HOST, HZERO_HFLE) {
return `${API_HOST}${HZERO_HFLE}`;
}
function changeVERSION_IS_OP(PLATFORM_VERSION) {
return `${PLATFORM_VERSION}` === 'OP'; // OP版
}
// #endregion
// #region changeRoute
window.changeRoute = function changeRoute(key, value) {
if (key && value) {
switch (key) {
case 'WEBSOCKET_URL':
WEBSOCKET_URL = value;
break;
case 'HZERO_PLATFORM':
HZERO_PLATFORM = value;
break;
case 'HZERO_HFLE':
HZERO_HFLE = value;
HZERO_FILE = changeHZERO_FILE(API_HOST, value);
break;
case 'HZERO_FILE':
HZERO_FILE = value;
break;
case 'VERSION_IS_OP':
VERSION_IS_OP = value;
break;
case 'PLATFORM_VERSION':
VERSION_IS_OP = changeVERSION_IS_OP(value);
break;
default:
console.error(`${key} is not exists`);
helpMethod();
break;
}
} else {
helpMethod(key);
}
};
// #endregion
// #region helpMethod
const helpMethodAssist = {
WEBSOCKET_URL: { changeConfig: ['WEBSOCKET_URL'], depBy: [] },
HZERO_PLATFORM: { changeConfig: ['HZERO_PLATFORM'], depBy: [] },
HZERO_HFLE: { changeConfig: ['HZERO_HFLE', 'HZERO_FILE'], depBy: [] },
HZERO_FILE: { changeConfig: ['HZERO_FILE'], depBy: ['HZERO_FILE', 'HZERO_FILE'] },
CLIENT_ID: { changeConfig: ['AUTH_URL'], depBy: [] },
VERSION_IS_OP: { changeConfig: ['VERSION_IS_OP'], depBy: ['VERSION_IS_OP'] },
PLATFORM_VERSION: { changeConfig: ['VERSION_IS_OP'], depBy: [] },
};
function helpMethod(key) {
if (key && helpMethodAssist[key]) {
console.error(
`${key} 会更改: [${helpMethodAssist[key].changeConfig.join(
', '
)}], 被级连更改: [${helpMethodAssist[key].depBy.join(', ')}]`
);
} else {
console.error('使用 changeRoute() 查看可以更改的参数');
console.error('使用 changeRoute("参数") 查看具体改变');
console.error('使用 changeRoute("参数", "参数值") 更改参数');
console.error(`可以更改的配置: [${Object.keys(helpMethodAssist).join(', ')}]`);
}
}
// #endregion
// #regioin exportsConfig
export {
CLIENT_ID,
WEBSOCKET_URL,
HZERO_PLATFORM,
HZERO_HFLE,
HZERO_FILE,
VERSION_IS_OP,
};
// #endregion