From 0092627935d5ab70102d2d8ce9e804d0d664a0df Mon Sep 17 00:00:00 2001 From: Luk Date: Sat, 21 Sep 2024 11:22:24 +0800 Subject: [PATCH] use assign-deep instead of deepmerge; add start_watching to reload dynamic envar files on file change. --- envar-tool.js | 120 +++++++++++++++++++++++++++----------------------- package.json | 6 +-- 2 files changed, 69 insertions(+), 57 deletions(-) diff --git a/envar-tool.js b/envar-tool.js index 3e93268..3d61220 100644 --- a/envar-tool.js +++ b/envar-tool.js @@ -1,6 +1,8 @@ const fs = require('fs') const path = require('path') -const deepmerge = require('deepmerge') +const chokidar = require('chokidar') +const assign_deep = require('assign-deep') +//const deepmerge = require('deepmerge') // https://github.com/jonschlinkert/assign-deep // 类似 Object.assign 直接赋值到第一个对象里。只下载2个包。assign 优选。 // https://github.com/jonschlinkert/merge-deep // 生成一个新对象。会下载7~8个包。 // https://github.com/TehShrike/deepmerge // 生成一个新对象。只下载1个包。 @@ -9,11 +11,25 @@ const deepmerge = require('deepmerge') const my = { envar: {} } module.exports = { + start_watching ({ envarFiles = ['./envar-base-dynamic.js', './envar-base-dynamic.gitignore.js'], rawEnvar = {} } = {}) { + chokidar.watch(envarFiles, { interval: 500 }).on('change', (onpath) => { + // .on('all', (event, onpath)) 但这时,即使server刚启动,也会调用到这里一次 + console.log('envarTool.start_watching: envar file changed:', onpath) + delete require.cache[require.resolve(path.resolve(onpath))] + try { + assign_deep(rawEnvar, require(path.resolve(onpath))) + console.log(`envarTool.start_watching: successfully reload ${onpath}`) + } catch (expt) { + console.log(`envarTool.start_watching: failed reload ${onpath}`) + } + }) + }, + /** 合并 envar files 和 commander parameters 中的环境变量。 * @param envarFiles: * - 字符串: 导入文件,内容应当是字符串数组,或者对象。 * - 字符串数组: 按顺序导入导入每个文件,后面文件里的变量覆盖前面的。 - * - 对象: 直接添加到 global.envar 上。 + * - 对象: 直接添加到 rawEnvar 上。 */ merge_envar ({ rawEnvar = {}, @@ -26,59 +42,55 @@ module.exports = { './envar-base-secret.gitignore.js', ], } = {}) { - if (!global.envar) { - global.envar = rawEnvar // 不知为何,必须定义成全局变量,才能保证多次require只执行一次。 + console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: `<<<<<<<< Configuring [${process.env.NODE_ENV}] Environment <<<<<<<<` }, '\n,') - console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: `<<<<<<<< Configuring [${process.env.NODE_ENV}] Environment <<<<<<<<` }, '\n,') - - console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: '- Loading Configuration Files (读取配置文件)' }, '\n,') - if (typeof envarFiles === 'string') { - // 例如当输入参数为 envarFiles = 'envar-base.js' 里面应当 module.exports 一个数组 - if (fs.existsSync(path.resolve(envarFiles))) { - envarFiles = require(path.resolve(envarFiles)) - } else { - console.warn({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - ${envarFiles} is missing.` }, '\n,') - envarFiles = undefined - } - } - - if (Array.isArray(envarFiles)) { - for (let configFile of envarFiles) { - if (fs.existsSync(path.resolve(configFile))) { - global.envar = deepmerge(global.envar, require(path.resolve(configFile))) - console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - ${configFile} is loaded.` }, '\n,') - } else { - console.warn({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - ${configFile} is missing.` }, '\n,') - } - } - } else if (typeof envarFiles === 'object') { - global.envar = deepmerge(global.envar, envarFiles) + console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: '- Loading Configuration Files (读取配置文件)' }, '\n,') + if (typeof envarFiles === 'string') { + // 例如当输入参数为 envarFiles = 'envar-base.js' 里面应当 module.exports 一个数组 + if (fs.existsSync(path.resolve(envarFiles))) { + envarFiles = require(path.resolve(envarFiles)) } else { - console.warn({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - unrecognized envarFiles!` }, '\n,') + console.warn({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - ${envarFiles} is missing.` }, '\n,') + envarFiles = undefined } - - if (process.argv.length > 2 && Array.isArray(global.envar.commanderOptions)) { - console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: '- Loading Command Line Parameters (载入命令行参数)' }, '\n,') - const commander = require('commander') - commander.version(global.envar.Base_Version || '0.0.1', '-v, --version') // 默认是 -V。如果要 -v,就要加 '-v --version' - for (let [key, param, desc] of global.envar.commanderOptions || []) { - commander.option(param, `${desc} Default = "${global.envar[key]}"`) - } - commander.parse(process.argv) - // console.log({_at:new Date().toJSON(),_from:'merge_envar', about: '- Merging Command Line Parameters into Configuration (把命令行参数值合并入配置)' },'\n,') - for (let key in commander) { - if (!/^_/.test(key) && typeof commander[key] === 'string') { - // commander 自带了一批 _开头的属性,过滤掉 - global.envar[key] = commander[key] - } - } - delete global.envar.commanderOptions - } - - console.log({ _at: new Date().toJSON(), _from: 'merge_envar', about: `>>>>>>>> Configured [${process.env.NODE_ENV}] Environment >>>>>>>>` }, '\n,') } - return global.envar + if (Array.isArray(envarFiles)) { + for (let configFile of envarFiles) { + if (fs.existsSync(path.resolve(configFile))) { + assign_deep(rawEnvar, require(path.resolve(configFile))) + console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - ${configFile} is loaded.` }, '\n,') + } else { + console.warn({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - ${configFile} is missing.` }, '\n,') + } + } + } else if (typeof envarFiles === 'object') { + assign_deep(rawEnvar, envarFiles) + } else { + console.warn({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - unrecognized envarFiles!` }, '\n,') + } + + if (process.argv.length > 2 && Array.isArray(rawEnvar.commanderOptions)) { + console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: '- Loading Command Line Parameters (载入命令行参数)' }, '\n,') + const commander = require('commander') + commander.version(rawEnvar.Base_Version || '0.0.1', '-v, --version') // 默认是 -V。如果要 -v,就要加 '-v --version' + for (let [key, param, desc] of rawEnvar.commanderOptions || []) { + commander.option(param, `${desc} Default = "${rawEnvar[key]}"`) + } + commander.parse(process.argv) + // console.log({_at:new Date().toJSON(),_from:'merge_envar', about: '- Merging Command Line Parameters into Configuration (把命令行参数值合并入配置)' },'\n,') + for (let key in commander) { + if (!/^_/.test(key) && typeof commander[key] === 'string') { + // commander 自带了一批 _开头的属性,过滤掉 + rawEnvar[key] = commander[key] + } + } + delete rawEnvar.commanderOptions + } + + console.log({ _at: new Date().toJSON(), _from: 'merge_envar', about: `>>>>>>>> Configured [${process.env.NODE_ENV}] Environment >>>>>>>>` }, '\n,') + + return rawEnvar }, /* 读取动态配置文件中的环境变量。 @@ -102,7 +114,7 @@ module.exports = { for (let dynamicFile of dynamicEnvarFiles) { if (fs.existsSync(path.resolve(dynamicFile))) { delete require.cache[require.resolve(path.resolve(dynamicFile))] // delete require.cache[fullpath] 不起作用,必须要加 require.resolve - dynamicEnvar = deepmerge(dynamicEnvar, require(path.resolve(dynamicFile))) // 在这里其实不需要 deepmerge + assign_deep(dynamicEnvar, require(path.resolve(dynamicFile))) // 在这里其实不需要 assign_deep console.info({ _at: new Date().toJSON(), _from: 'get_dynamic_envar', about: ` - ${dynamicFile} is parsed.` }, '\n,') } else { console.warn({ _at: new Date().toJSON(), _from: 'get_dynamic_envar', about: ` - ${dynamicFile} is missing.` }, '\n,') @@ -121,7 +133,7 @@ module.exports = { * 需要输出当前环境变量时,必须调用本函数,避免机密信息被输出。 */ mask_secret_envar ({ rawEnvar, secretEnvarFiles = ['./envar-base-secret.js', './envar-base-secret.gitignore.js'] } = {}) { - let envar = JSON.parse(JSON.stringify(rawEnvar || global.envar)) // 复制一份,避免污染 + let envar = JSON.parse(JSON.stringify(rawEnvar)) // 复制一份,避免污染 let secretEnvar = {} @@ -138,7 +150,7 @@ module.exports = { if (Array.isArray(secretEnvarFiles)) { for (let secretFile of secretEnvarFiles) { if (fs.existsSync(path.resolve(secretFile))) { - secretEnvar = deepmerge(secretEnvar, require(path.resolve(secretFile))) // 在这里其实不需要 deepmerge + assign_deep(secretEnvar, require(path.resolve(secretFile))) // 在这里其实不需要 assign_deep console.info({ _at: new Date().toJSON(), _from: 'mask_secret_envar', about: ` - ${secretFile} is parsed.` }, '\n,') } else { console.warn({ _at: new Date().toJSON(), _from: 'mask_secret_envar', about: ` - ${secretFile} is missing.` }, '\n,') @@ -226,7 +238,7 @@ module.exports = { if (refresh) { delete require.cache[require.resolve(path.resolve(envarFile))] // delete require.cache[fullpath] 不起作用,必须要加 require.resolve } - envar = deepmerge(envar, require(path.resolve(envarFile))) + assign_deep(envar, require(path.resolve(envarFile))) console.info({ _at: new Date().toJSON(), _from: 'merge_envar_files', about: ` - ${envarFile} is parsed.` }, '\n,') } else { console.warn({ _at: new Date().toJSON(), _from: 'merge_envar_files', about: ` - ${envarFile} is missing.` }, '\n,') diff --git a/package.json b/package.json index 35f6f66..2ef40a1 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,10 @@ "version": "0.1.0", "private": true, "dependencies": { - "commander": "^4.1.1", - "deepmerge": "^4.2.2" + "assign-deep": "^1.0.1", + "chokidar": "^4.0.0", + "commander": "^4.1.1" }, - "devDependencies": {}, "scripts": { "setup": "npm install" },