node-config 模块根据 ENV 环境变量不同加载响应的配置文件
上一篇博文和大家分享了ENV定制开发,测试,发布环境变量.
定制了以后如何来用,今天这篇就是要介绍如何使用自定义的不同环境变量.
大概有些同学会有疑问.
- 为什么各种环境不直接配成一致的.
如果可以这么做的话,再好不过的.
- 什么时候可能需要不同的配置.
如果你想在开发环境下打印出log ,但是在正式运行环境不想打印log.
你想在开发环境加载原 javascript 文件, 在正式运行环境下压缩javascript 文件.
或者你想在开发环境加载一套 config 配置,在正式运行环境加载另外一套 config 配置.
等等......一切你需要定制化的时候.
3. 我需要一个普通的json配置文件即可,为何要用node-config模块
都可以,只要你喜欢
普通json 去增删配置节点时,需要你手动解析,判断,加载.....
node-config 自动加载某指定配置文件夹下所有指定名称的 js ,json ,json5, toml ,coffee ,yaml , yml ......等等
判断节点是否存在,追加配置等等更方便, 存在的就是合理的, 目前 740个 star还是很受人欢迎的npm包.
node-config 模块,看名字应该是帮助我们加载,管理配置文件的,确实是这样.
github官方地址:https://github.com/lorenwest/node-config
使用:
$ npm install config --save
$ mkdir config
上面创建的 config 文件夹就是存放不同配置环境下的配置文件,假设我们有如下配置文件
default.json
develop.json
test.json
production.json
默认的配置文件,里面的公用的,基础的配置信息.
其他配置文件里都是差异化定制配置信息,
develop.json 开发环境配置
test.json 测试环境配置
production.json 正式环境配置
config 如何能智能的识别出默认配置,然后根据不同环境变量去加载指定的配置文件呢?
其实也没有那么智能,这些操作是我们自己来做的,所以我们还需要一个掌控全局的 js 文件 index.js
这个掌控全局的 index.js 文件有什么功能呢?
-
读取默认共享配置, config模块默认读取 default.json (当然你也可以指定,或者EVN变量设置)
-
根据不同环境变量加载不同的配置信息
-
把2中定制的配置信息追加到1共享配置中
先来看下index.js 文件的写法:
var _ = require('underscore');
var path = require('path');
var default_config = require('./default.json'); //加载默认共享配置
//自启动匿名函数
module.exports = (function () {
var version = (process.env.YIJIEBUYI_VERSION||'develop').toLowerCase(), ver_config, config;
//首先读取EVN 环境变量 YIJIEBUYI_VERSION ,如果此变量未定义,赋值 develop (加载 develop.json )
try {
ver_config = require('./' + version);
// 加载环境变量指定的配置,如果 YIJIEBUYI_VERSION=test 此处加载 test.json
} catch (err) {
console.log("Cannot find version " + version + " config file!!!");
process.exit(-1);
}
config = _.extend({'version':version}, default_config, ver_config);
// extend 是underscore 的一个api ,作用就是 把 default_config(默认配置),自定义配置(ver_config) 复制全部属性到 {'version':version}此对象上.如果有重复属性(后面的会覆盖前面的属性值)
//下面可以给 config 对象添加一些属性,方便程序使用
config.is_production = config.version === 'production';
config.is_test = config.version === 'test';
return config;
})();
上面每句代码都在后面加上了注释.
这段脚本首先会加载default.json
然后根据你当前环境变量 YIJIEBUYI_VERSION 的值来决定接下来加载哪个配置文件,然后追加到 config 对象上.
config模块简单api介绍:
如果你阅读config 模块源代码,/lib/config.js 可以发现他暴露了几个方法:
Config.prototype.get(属性名)
我们最常用的方法之一,根据配置里的属性名获取属性值.
Config.prototype.has(属性名)
判断某个属性名在配置文件里能否找到,是否存在此属性定义
还有一个非常非常重要的对象,定义在 config 的 util 属性上.
var util = Config.prototype.util = {};
这个对象上定义了很多方法,我们只简单介绍一个
util.loadFileConfigs=function(){ ..... }
有兴趣的直接去阅读源代码.
其中这个方法读取了 NODE_ENV 环境变量,如果没有,赋默认值 development
然后读取了 NODE_CONFIG_DIR 环境变量,如果没有,赋默认值 config ,这个变量决定你的的配置文件所在目录(可以绝对路径,也可以相对路径)相对路径的时候,一定要是项目中的一个目录(不解释)
if (CONFIG_DIR.indexOf('.') === 0) {
CONFIG_DIR = process.cwd() + '/' + CONFIG_DIR;
}
如果配置文件所在目录以 . 开始,就是相对路径,根据 process.cwd() 获取项目所在文件夹目录. 进而找到配置文件目录.
var baseNames = ['default', NODE_ENV, hostName, hostName + '-' + NODE_ENV, 'local', 'local-' + NODE_ENV];
var extNames = ['js', 'json', 'json5', 'toml', 'coffee', 'iced', 'yaml', 'yml', 'cson', 'properties'];
baseNames.forEach(function(baseName) {
extNames.forEach(function(extName) {
// Try merging the config object into this object
var fullFilename = CONFIG_DIR + '/' + baseName + '.' + extName;
var configObj = util.parseFile(fullFilename);
if (configObj) {
util.extendDeep(config, configObj);
}
// See if the application instance file is available
if (APP_INSTANCE) {
fullFilename = CONFIG_DIR + '/' + baseName + '-' + APP_INSTANCE + '.' + extName;
configObj = util.parseFile(fullFilename);
if (configObj) {
util.extendDeep(config, configObj);
}
}
});
});
上面2个数组:
1个是文件名数组
1个是扩展名数组
然后2个foreach 会拼接出 N*M 种文件格式. (N 是数组一元素个数,M 是数组二元素个数)
根据组合出来的文件格式去加载本地文件.
如果有配置内容
fullFilename = CONFIG_DIR + '/' + baseName + '-' + APP_INSTANCE + '.' + extName;
configObj = util.parseFile(fullFilename);
if (configObj) {
util.extendDeep(config, configObj);
}
util.extendDeep 方法会把读取到的配置内容放到configSources对象中:
util.extendDeep(config, envConfig);
configSources.push({
name: "$NODE_CONFIG",
parsed: envConfig,
});
