环境变量配置
环境变量配置
srm-front/config/compile{Profile}Env.js
- 环境变量存放的位置
环境变量
// srm-front/config/compileBuildEnv.js
module.exports = {
// 自定义的登陆,登出地址, 没有配置 会根据配置的网关地址 和 oauth 服务生成
// LOGIN_URL: '',
// LOGOUT_URL: '',
// 项目的访问基地址
BASE_PATH: '/',
// PUBLIC_URL: '/app',
// 项目是 OP/SAAS
PLATFORM_VERSION: 'BUILD_PLATFORM_VERSION',
// websocket 地址
WEBSOCKET_HOST: 'BUILD_WEBSOCKET_HOST',
// 工作流地址
BPM_HOST: 'BUILD_BPM_HOST',
// 工作流你编辑器地址
WFP_EDITOR: 'BUILD_API_HOST',
// oauth 访问 客户端id
CLIENT_ID: 'BUILD_CLIENT_ID',
// 网关地址
API_HOST: 'BUILD_API_HOST',
// 在 build 时 不生成 source-map
GENERATE_SOURCEMAP: false,
// 服务合并的环境变量
routeMap: JSON.stringify({
"/hpfm": "/hpfm",
"/iam": "/iam",
"/hdtt": "/hdtt",
"/hmsg": "/hmsg",
"/hptl": "/hptl",
"/hwfl": "/hwfl",
"/hdtw": "/hdtw",
"/hsdr": "/hsdr",
"/hsgp": "/hsgp",
"/hitf": "/hitf",
"/hfle": "/hfle",
"/oauth": "/oauth",
"/hagd": "/hagd",
"/himp": "/himp",
"/hrpt": "/hrpt",
"/hcnf": "/hcnf",
"/hwfp": "/hwfp",
"/hnlp": "/hnlp",
"/hpay": "/hpay",
"/hmnt": "/hmnt"
}),
};
分类
编译环境变量
在编译代码时需要用到的环境变量
BASE_PATH, PUBLIC_URL 等
运行环境变量
在项目中使用的环境变量, 需要在config中配置
BASE_PATH, API_HOST 等
项目中使用到的 可通过环境变量的配置的变量 全部统一通过 ApiConfig 生成
ApiConfig
编写
- hzero-front 使用生成的方式编写 utils/config.js 文件
- 以下文档 说明了 如何 配置自己的 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: ['HZERO_HXXX'],
get: (HZERO_HXXX) => {
return `${HZERO_HXXX}/logout`;
},
},
};
实际文件
- 除了 scripts/genConfig.js 外 其他文件都有删减
- 其他项目如果也需要使用 apiConfig, 需要将 scripts/genConfig.js中的 changeRoute 方法 改名为 {projectName}ChangeRoute
- 配置
srm-front/packages/spfm-front
的webpack别名配置 - 配置
其他模块
和主工程
的webpack别名配置
主模块webpack配置srm-front/packages/spfm-front
srm-front/packages/spfm-front/config/alias.js
module.exports = {
'@': path.resolve(__dirname, '../src'),
_config: path.resolve(__dirname, '../src/config.js'),
};
其他模块
和主工程
module.exports = {
'@': path.resolve(__dirname, '../src'),
_config: 'spfm-front/lib',
};
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 = {
VERSION: 'v1',
HZERO_HXXX: {
init: () => {
return "'/hxxx'";
},
route: true,
},
CLIENT_ID: {
init: () => {
return '`${process.env.CLIENT_ID}`';
},
noChange: true,
},
AUTH_LOGOUT_URL: {
deps: ['HZERO_HXXX'],
get: (HZERO_HXXX) => {
return `${HZERO_HXXX}/logout`;
},
},
};
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/utils/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
let VERSION = 'v1';
let HZERO_HXXX = routeMap['/hxxx'] || '/hxxx';
const CLIENT_ID = `${process.env.CLIENT_ID}`;
let AUTH_LOGOUT_URL = changeAUTH_LOGOUT_URL(HZERO_HXXX);
// #endregion
// #region changeConfig Funcs
function changeAUTH_LOGOUT_URL(HZERO_HXXX) {
return `${HZERO_HXXX}/logout`;
}
// #endregion
// #region changeRoute
window.srmChangeRoute = function changeRoute(key, value) {
if (key && value) {
switch (key) {
case 'VERSION':
VERSION = value;
break;
case 'HZERO_HXXX':
HZERO_HXXX = value;
AUTH_LOGOUT_URL = changeAUTH_LOGOUT_URL(value);
break;
case 'AUTH_LOGOUT_URL':
AUTH_LOGOUT_URL = value;
break;
default:
console.error(`${key} is not exists`);
helpMethod();
break;
}
} else {
helpMethod(key);
}
};
// #endregion
// #region helpMethod
const helpMethodAssist = {
VERSION: { changeConfig: ['VERSION'], depBy: [] },
HZERO_HXXX: { changeConfig: ['HZERO_HXXX', 'AUTH_LOGOUT_URL'], depBy: [] },
AUTH_LOGOUT_URL: { changeConfig: ['AUTH_LOGOUT_URL'], depBy: ['AUTH_LOGOUT_URL'] },
};
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 { VERSION, HZERO_HXXX, CLIENT_ID, AUTH_LOGOUT_URL };
// #endregion