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, });