Node.js Conf 配置库要点分析 和 使用注意事项
Electron 中有个 electron-store,深入源码去看,发现其依赖Node.js的配置库 Conf,只是在这个基础上追加主进程和其他渲染进程 proload.js 通信的环节,让你在使用时无感这个过程,实际上Electron-store 超简单,就是在主进程中直接获取,在渲染进程中,通过sendSync获取下面这个参数,主进程必须实例化一个监听事件,渲染进程从这边获取用户目录和 App 版本
const appData = {defaultCwd: app.getPath('userData'),appVersion: app.getVersion()};
Conf的各类配置
选项名 | 类型 | 默认值 | 说明 | 示例 |
defaults | object | undefined | 指定配置的默认值,当配置文件中缺少某键时返回默认值。确保关键配置始终有值,防止程序因缺失配置出错。 | const config = new Conf({ defaults: { theme: 'dark', notifications: true } });console.log(config.get('theme')); // 'dark' |
configName | string | 'config' | 指定配置文件名称(不含扩展名),生成的文件名为 configName.json 。 | const config = new Conf({ configName: 'settings' }); // 生成 settings.json |
projectName | string | 从最近的 package.json 的 name 字段获取 | 指定项目名称,用于确定配置文件存储路径(通常在系统用户配置目录下的 project-name 文件夹)。避免不同项目配置冲突。 | const config = new Conf({ projectName: 'my-app' }); // 存储在 my-app 文件夹 |
projectVersion | string | 从最近的 package.json 的 version 字段获取 | 指定项目版本,存储为配置文件元数据,用于配置迁移或版本兼容性处理。 | const config = new Conf({ projectVersion: '1.0.0' }); |
cwd | string | process.cwd() | 指定查找 package.json 的目录,影响 projectName 和 projectVersion 的自动获取,或用于自定义配置文件路径。 | const config = new Conf({ cwd: '/path/to/project' }); |
projectSuffix | string | 'nodejs' | 在项目名称后附加后缀,影响存储路径(常见于 Windows 等系统)。可设为空字符串 '' 移除后缀,或自定义后缀。 | const config = new Conf({ projectName: 'my-app', projectSuffix: 'prod' }); // 路径含 my-app-prod |
fileExtension | string | 'json' | 指定配置文件扩展名,默认为 .json 。可配合 serialize 和 deserialize 使用其他格式。 | const config = new Conf({ fileExtension: 'conf' }); // 生成 config.conf |
accessProperties | object | undefined | 高级功能,允许通过点状路径(dot-notation)直接访问嵌套属性,映射到顶层属性。 | const config = new Conf({ accessProperties: { size: 'window.size' } });config.size = { width: 100, height: 200 };console.log(config.get('window.size')); // { width: 100, height: 200 } |
watch | boolean | false | 启用配置文件变动监听。若设为 true ,当外部修改配置文件(如手动编辑 JSON)时, conf 自动重新加载,并可通过 onDidChange 事件响应变化。 | const config = new Conf({ watch: true });config.onDidChange('port', (newValue, oldValue) => console.log(`Port changed from ${oldValue} to ${newValue}`)); |
serialize | function | value => JSON.stringify(value, null, '\t') | 自定义序列化函数,在写入配置文件前将数据转换为字符串。默认使用带缩进的 JSON 格式。 | const config = new Conf({ serialize: value => JSON.stringify(value) }); // 无缩进 JSON |
deserialize | function | value => JSON.parse(value) | 自定义解析函数,在读取配置文件后将字符串转换为 对象。默认使用 JSON.parse 。 | const config = new Conf({ deserialize: text => JSON.parse(text.replace(/'/g, '"')) }); |
encryptionKey | `string | Buffer | object` | undefined |
schema | object | undefined | 定义 JSON Schema 验证配置数据,需为 JSON Schema 的 properties 对象。每个键对应配置项,值定义类型、约束及默认值。默认值会被 defaults 覆盖。 | const schema = { foo: { type: 'number', maximum: 100, minimum: 1, default: 50 } };const config = new Conf({ schema });config.set('foo', 'invalid'); // 抛出错误 |
accessPropertiesByDotNotation | boolean | true | 控制是否支持点状路径访问嵌套属性。若为 false ,点状字符串(如 foo.bar )被视为单一键。 | const config = new Conf({ accessPropertiesByDotNotation: false });config.set('foo.bar', 'baz');console.log(config.get('foo.bar')); // 'baz' |
migrations | object | undefined | 定义版本迁移函数,键为版本号,值为迁移函数。需配合 projectVersion 使用,处理旧版本配置升级。 | const config = new Conf({ migrations: { '2.0.0': store => store.set('newKey', 'value') }, projectVersion: '2.0.0' }); |
关键功能说明
-
文件变动监听:
-
通过 watch: true 启用监听功能,结合 onDidChange 方法可实时响应配置变化。
-
示例场景:当用户手动编辑 config.json 文件(如更改端口号),程序可自动检测并重启服务以应用新配置。
-
-
加密存储:
-
使用 encryptionKey 保护敏感数据,但需注意密钥管理安全,避免硬编码在代码中。
-
-
嵌套属性访问:
-
默认支持点状路径(如 config.get('foo.bar')),通过 accessPropertiesByDotNotation 可禁用,或用 accessProperties 映射属性。
-
-
默认值与验证:
-
defaults 提供兜底值,schema 确保数据格式正确,结合使用可提高配置可靠性。
-
-
自定义序列化/反序列化:
-
通过 serialize 和 deserialize 支持非 JSON 格式(如 YAML),但需自行实现格式转换逻辑。
-
使用注意事项
-
权限问题:设置 projectName 和 projectSuffix 时,确保进程有权读写系统配置目录(如 ~/Library/Preferences 或 ~/.config)。运行脚本时避免混用 sudo 和非 sudo,否则可能导致权限错误。
-
性能考虑:启用 watch 会增加文件系统监控开销,适合动态配置场景;若配置静态,可禁用以提升性能。
-
加密安全性:encryptionKey 仅用于数据混淆,非强加密。敏感数据建议结合其他安全措施(如环境变量或密钥管理服务)。
-
版本迁移:使用 migrations 时,确保 projectVersion 准确,以避免重复执行迁移逻辑。
示例综合应用
以下是一个综合示例,展示如何使用多个选项实现配置管理、监听和加密:
const Conf = require('conf');const config = new Conf({configName: 'app-config',projectName: 'my-app',projectSuffix: '',watch: true,encryptionKey: 'my-secret-key',defaults: {port: 3000,theme: 'light'},schema: {port: { type: 'number', minimum: 1024, maximum: 65535, default: 3000 },theme: { type: 'string', enum: ['light', 'dark'] }}
});// 监听配置变化
config.onDidChange('port', (newValue, oldValue) => {console.log(`Port changed from ${oldValue} to ${newValue}`);// 例如:重启服务器以应用新端口
});// 设置配置
config.set('port', 8080); // 自动写入加密后的 app-config.json
console.log(config.get('port')); // 8080
console.log(config.get('theme')); // 'light'(来自 defaults)
Conf 的迁移逻辑
- config.json 文件只保留最后升级的版本号,若没有配置migrations和projectVersion两个字段,则config.json中不会出现__internal__.migrations.version字段
- 遵循连续性升级规则,会将当前的版本号与升级列表版本号一一比对,获得需要升级的版本逻辑
const Store = require('electron-store');
const path = require('path');
const fs = require('fs');// 初始化 electron-store 实例
const store = new Store({// 项目名称,决定配置文件存储路径(如 ~/.config/my-app/config.json)projectName: 'my-app',// 目标版本号,指定要迁移到的版本projectVersion: '1.1.0',// 配置文件名(默认 config.json)configName: 'config',// 文件扩展名(默认 json)fileExtension: 'json',// 配置存储目录(可选,默认使用 env-paths 推断)cwd: path.join(__dirname, 'config'),// 启用文件监听,响应外部修改watch: true,// 默认配置值defaults: {theme: 'light',port: 3000},// JSON Schema 验证(可选,确保配置格式正确)schema: {theme: {type: 'string',enum: ['light', 'dark'],default: 'light'},port: {type: 'number',minimum: 1024,maximum: 65535,default: 3000},featureA: {type: 'boolean',default: false},featureB: {type: 'string',default: 'disabled'}},// 迁移规则,定义版本升级逻辑migrations: {'1.0.0': store => {console.log('Migrating to 1.0.0');// 添加新配置项store.set('featureA', true);// 示例:重命名旧键if (store.has('oldKey')) {store.set('newKey', store.get('oldKey'));store.delete('oldKey');}},'1.1.0': store => {console.log('Migrating to 1.1.0');// 添加或更新配置项store.set('featureB', 'enabled');// 示例:转换配置格式if (store.has('theme')) {store.set('theme', store.get('theme').toLowerCase());}}},// 在每次迁移前执行的钩子,用于调试或日志记录beforeEachMigration: (store, { fromVersion, toVersion, finalVersion, versions }) => {console.log(`Migrating from ${fromVersion} to ${toVersion} (final: ${finalVersion}, versions: ${versions.join(', ')})`);},// 序列化/反序列化(可选,定制 JSON 格式)serialize: value => JSON.stringify(value, null, 2), // 美化 JSON 输出deserialize: value => JSON.parse(value),// 文件权限(默认 0o666)configFileMode: 0o666,// 是否清除无效配置(例如,JSON 解析错误时)clearInvalidConfig: true,// 是否启用点状路径访问(默认 true)accessPropertiesByDotNotation: true
});// 监听配置文件变化(需要 watch: true)
store.onDidAnyChange(() => {console.log('Config file changed externally, reloading...');console.log('Current config:', store.store);
});// 示例:监听特定键的变化
store.onDidChange('theme', (newValue, oldValue) => {console.log(`Theme changed from ${oldValue} to ${newValue}`);
});// 示例:操作配置
console.log('Initial config:', store.store);
store.set('port', 8080); // 更新配置,自动写入 config.json
console.log('Updated port:', store.get('port'));// 检查迁移版本
console.log('Current version:', store.get('__internal__.migrations.version'));