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'));