本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
这是源码共读的第10期 | configstore 存储
前言
configstore 是一个轻量级的 本地持久化的存储实现,其本质就是对于本地JSON文件的键值对读写,我们无需考虑在何处以及如何去加载它
使用
npm install configstore
import fs from 'node:fs';
import Configstore from 'configstore';
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
// Create a Configstore instance.
const config = new Configstore(packageJson.name, {foo: 'bar'});
console.log(config.get('foo'));
//=> 'bar'
config.set('awesome', true);
console.log(config.get('awesome'));
//=> true
// Use dot-notation to access nested properties.
config.set('bar.baz', true);
console.log(config.get('bar'));
//=> {baz: true}
config.delete('awesome');
console.log(config.get('awesome'));
//=> undefined
源码
index.js 整体源码100行出头
初始化和常量
const configDirectory = xdgConfig || path.join(os.tmpdir(), uniqueString());
const permissionError = 'You don\'t have access to this file.';
const mkdirOptions = {mode: 0o0700, recursive: true};
const writeFileOptions = {mode: 0o0600};
xdgConfig 通过 xdg-basedir 获取用户目录下的配置文件路径, path.join(os.tmpdir(), uniqueString())
获取的是当前用户目录 + 随机字符串的路径
constructor(id, defaults, options = {}) {
const pathPrefix = options.globalConfigPath ?
path.join(id, 'config.json') :
path.join('configstore', `${id}.json`);
// 如果没有传入options则取 xdgConfig + pathPrefix的拼接目录
// 比如我本地的在这里 C:\Users\Harexs\.config\configstore
this._path = options.configPath || path.join(configDirectory, pathPrefix);
// 默认对象 解构覆盖值
if (defaults) {
this.all = {
...defaults,
...this.all
};
}
}
all – get/set
在get 和 set 中会对 all
进行访问,所以这里先看 它对应的 getter/setter
, 它也是核心的读写属性
try {
return JSON.parse(fs.readFileSync(this._path, 'utf8'));
} catch (error) {
// Create directory if it doesn't exist
if (error.code === 'ENOENT') {
return {};
}
// Improve the message of permission errors
if (error.code === 'EACCES') {
error.message = `${error.message}\n${permissionError}\n`;
}
// Empty the file if it encounters invalid JSON
if (error.name === 'SyntaxError') {
writeFileAtomic.sync(this._path, '', writeFileOptions);
return {};
}
throw error;
}
读取时,使用graceful-fs
对 本地文件进行访问,将其取出后JSON化, 如果不存在文件或报错根据情况进行处理
try {
// Make sure the folder exists as it could have been deleted in the meantime
fs.mkdirSync(path.dirname(this._path), mkdirOptions);
writeFileAtomic.sync(this._path, JSON.stringify(value, undefined, '\t'), writeFileOptions);
} catch (error) {
// Improve the message of permission errors
if (error.code === 'EACCES') {
error.message = `${error.message}\n${permissionError}\n`;
}
throw error;
}
触发setter
时,创建对应的文件和目录,将对象重新进行覆写
增删改查
dotProp 是一个对象属性操作的包,它允许我们可以用点的形式去操作和访问对象,例如 xxx.xxx
// 从返回的key获取值
get(key) {
return dotProp.get(this.all, key);
}
//先得到完整的对象,再根据传递参数的数量进行不同的处理
set(key, value) {
const config = this.all;
if (arguments.length === 1) {
for (const k of Object.keys(key)) {
dotProp.set(config, k, key[k]);
}
} else {
dotProp.set(config, key, value);
}
this.all = config;
}
has(key) {
return dotProp.has(this.all, key);
}
delete(key) {
const config = this.all;
dotProp.delete(config, key);
this.all = config;
}
clear() {
this.all = {};
}
总结
其最核心就是对于all
的属性访问操作符,通过dotProp 对 属性的夹子(get/set)进行操作, 而其他增删改查则是最基本的对象属性操作,我们可以依靠这个思路 学习写一个不依赖包的轮子, 并尝试使用Proxy来处理, 和使用split 分割的思路来支持xx.xx.xx
的操作方式:
harexs-store
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END