use assign-deep instead of deepmerge; add start_watching to reload dynamic envar files on file change.

This commit is contained in:
Luk 2024-09-21 11:22:24 +08:00
parent 73a084be8b
commit 0092627935
2 changed files with 69 additions and 57 deletions

View File

@ -1,6 +1,8 @@
const fs = require('fs') const fs = require('fs')
const path = require('path') 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/assign-deep // 类似 Object.assign 直接赋值到第一个对象里。只下载2个包。assign 优选。
// https://github.com/jonschlinkert/merge-deep // 生成一个新对象。会下载78个包。 // https://github.com/jonschlinkert/merge-deep // 生成一个新对象。会下载78个包。
// https://github.com/TehShrike/deepmerge // 生成一个新对象。只下载1个包。 // https://github.com/TehShrike/deepmerge // 生成一个新对象。只下载1个包。
@ -9,11 +11,25 @@ const deepmerge = require('deepmerge')
const my = { envar: {} } const my = { envar: {} }
module.exports = { 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 /** envar files commander parameters
* @param envarFiles: * @param envarFiles:
* - 字符串: 导入文件内容应当是字符串数组或者对象 * - 字符串: 导入文件内容应当是字符串数组或者对象
* - 字符串数组: 按顺序导入导入每个文件后面文件里的变量覆盖前面的 * - 字符串数组: 按顺序导入导入每个文件后面文件里的变量覆盖前面的
* - 对象: 直接添加到 global.envar * - 对象: 直接添加到 rawEnvar
*/ */
merge_envar ({ merge_envar ({
rawEnvar = {}, rawEnvar = {},
@ -26,9 +42,6 @@ module.exports = {
'./envar-base-secret.gitignore.js', './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,') console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: '- Loading Configuration Files (读取配置文件)' }, '\n,')
@ -45,40 +58,39 @@ module.exports = {
if (Array.isArray(envarFiles)) { if (Array.isArray(envarFiles)) {
for (let configFile of envarFiles) { for (let configFile of envarFiles) {
if (fs.existsSync(path.resolve(configFile))) { if (fs.existsSync(path.resolve(configFile))) {
global.envar = deepmerge(global.envar, require(path.resolve(configFile))) assign_deep(rawEnvar, require(path.resolve(configFile)))
console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - ${configFile} is loaded.` }, '\n,') console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - ${configFile} is loaded.` }, '\n,')
} else { } else {
console.warn({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - ${configFile} is missing.` }, '\n,') console.warn({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - ${configFile} is missing.` }, '\n,')
} }
} }
} else if (typeof envarFiles === 'object') { } else if (typeof envarFiles === 'object') {
global.envar = deepmerge(global.envar, envarFiles) assign_deep(rawEnvar, envarFiles)
} else { } else {
console.warn({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - unrecognized envarFiles!` }, '\n,') console.warn({ _at: new Date().toJSON(), _from: 'merge_envar', about: ` - unrecognized envarFiles!` }, '\n,')
} }
if (process.argv.length > 2 && Array.isArray(global.envar.commanderOptions)) { if (process.argv.length > 2 && Array.isArray(rawEnvar.commanderOptions)) {
console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: '- Loading Command Line Parameters (载入命令行参数)' }, '\n,') console.info({ _at: new Date().toJSON(), _from: 'merge_envar', about: '- Loading Command Line Parameters (载入命令行参数)' }, '\n,')
const commander = require('commander') const commander = require('commander')
commander.version(global.envar.Base_Version || '0.0.1', '-v, --version') // 默认是 -V。如果要 -v就要加 '-v --version' commander.version(rawEnvar.Base_Version || '0.0.1', '-v, --version') // 默认是 -V。如果要 -v就要加 '-v --version'
for (let [key, param, desc] of global.envar.commanderOptions || []) { for (let [key, param, desc] of rawEnvar.commanderOptions || []) {
commander.option(param, `${desc} Default = "${global.envar[key]}"`) commander.option(param, `${desc} Default = "${rawEnvar[key]}"`)
} }
commander.parse(process.argv) commander.parse(process.argv)
// console.log({_at:new Date().toJSON(),_from:'merge_envar', about: '- Merging Command Line Parameters into Configuration (把命令行参数值合并入配置)' },'\n,') // console.log({_at:new Date().toJSON(),_from:'merge_envar', about: '- Merging Command Line Parameters into Configuration (把命令行参数值合并入配置)' },'\n,')
for (let key in commander) { for (let key in commander) {
if (!/^_/.test(key) && typeof commander[key] === 'string') { if (!/^_/.test(key) && typeof commander[key] === 'string') {
// commander 自带了一批 _开头的属性过滤掉 // commander 自带了一批 _开头的属性过滤掉
global.envar[key] = commander[key] rawEnvar[key] = commander[key]
} }
} }
delete global.envar.commanderOptions delete rawEnvar.commanderOptions
} }
console.log({ _at: new Date().toJSON(), _from: 'merge_envar', about: `>>>>>>>> Configured [${process.env.NODE_ENV}] Environment >>>>>>>>` }, '\n,') console.log({ _at: new Date().toJSON(), _from: 'merge_envar', about: `>>>>>>>> Configured [${process.env.NODE_ENV}] Environment >>>>>>>>` }, '\n,')
}
return global.envar return rawEnvar
}, },
/* /*
@ -102,7 +114,7 @@ module.exports = {
for (let dynamicFile of dynamicEnvarFiles) { for (let dynamicFile of dynamicEnvarFiles) {
if (fs.existsSync(path.resolve(dynamicFile))) { if (fs.existsSync(path.resolve(dynamicFile))) {
delete require.cache[require.resolve(path.resolve(dynamicFile))] // delete require.cache[fullpath] 不起作用,必须要加 require.resolve 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,') console.info({ _at: new Date().toJSON(), _from: 'get_dynamic_envar', about: ` - ${dynamicFile} is parsed.` }, '\n,')
} else { } else {
console.warn({ _at: new Date().toJSON(), _from: 'get_dynamic_envar', about: ` - ${dynamicFile} is missing.` }, '\n,') 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'] } = {}) { 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 = {} let secretEnvar = {}
@ -138,7 +150,7 @@ module.exports = {
if (Array.isArray(secretEnvarFiles)) { if (Array.isArray(secretEnvarFiles)) {
for (let secretFile of secretEnvarFiles) { for (let secretFile of secretEnvarFiles) {
if (fs.existsSync(path.resolve(secretFile))) { 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,') console.info({ _at: new Date().toJSON(), _from: 'mask_secret_envar', about: ` - ${secretFile} is parsed.` }, '\n,')
} else { } else {
console.warn({ _at: new Date().toJSON(), _from: 'mask_secret_envar', about: ` - ${secretFile} is missing.` }, '\n,') console.warn({ _at: new Date().toJSON(), _from: 'mask_secret_envar', about: ` - ${secretFile} is missing.` }, '\n,')
@ -226,7 +238,7 @@ module.exports = {
if (refresh) { if (refresh) {
delete require.cache[require.resolve(path.resolve(envarFile))] // delete require.cache[fullpath] 不起作用,必须要加 require.resolve 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,') console.info({ _at: new Date().toJSON(), _from: 'merge_envar_files', about: ` - ${envarFile} is parsed.` }, '\n,')
} else { } else {
console.warn({ _at: new Date().toJSON(), _from: 'merge_envar_files', about: ` - ${envarFile} is missing.` }, '\n,') console.warn({ _at: new Date().toJSON(), _from: 'merge_envar_files', about: ` - ${envarFile} is missing.` }, '\n,')

View File

@ -5,10 +5,10 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"commander": "^4.1.1", "assign-deep": "^1.0.1",
"deepmerge": "^4.2.2" "chokidar": "^4.0.0",
"commander": "^4.1.1"
}, },
"devDependencies": {},
"scripts": { "scripts": {
"setup": "npm install" "setup": "npm install"
}, },