【源码共读】第10期 | configstore 存储

1. 前言

2. configstore是什么

configstore是一个简单的配置存储库,用于在Node.js应用程序中保存数据。它提供了一种简单的方式来读取、写入和管理配置数据,这些数据以JSON格式存储在磁盘上的文件中。

使用configstore有以下几个好处:

  1. 简化配置数据管理:使用configstore可以将配置数据以键值对的形式存储,以便更轻松地读取和修改配置。

  2. 方便的配置文件操作:configstore自动管理配置文件的存储路径,并提供了保存和读取配置文件的功能。

  3. 默认值和数据验证:configstore允许设置配置项的默认值,并在读取配置数据时使用该默认值。这是很有用的,当某个配置项的值尚未设置时,configstore可以提供一个合理的默认值,避免了因为配置数据缺失而导致的错误。

  4. 数据持久化:configstore将配置数据以JSON格式存储在磁盘上的文件中,从而确保数据的持久化。

  5. 轻量且易于使用:configstore是一个轻量级的模块,易于安装和使用。它具有简单的API,不需要额外的库或依赖项。

3. 源码解析

js 复制代码
import path from 'path'; // path 主要用处处理文件路径
import os from 'os'; // os 模块提供了一些基本的系统操作函数
import fs from 'graceful-fs'; // 文件系统模块 graceful-fs 是fs的替代品,进行了各种改进
import {xdgConfig} from 'xdg-basedir';// 跨平台的方法来获取常用的配置目录路径,如用户的配置目录和缓存目录。
import writeFileAtomic from 'write-file-atomic';// fs.writeFile的扩展,使其操作原子化,并允许您设置所有权。
import dotProp from 'dot-prop'; // dot-prop 用于获取对象的属性
import uniqueString from 'unique-string';// 生成一个唯一的随机字符串

const configDirectory = xdgConfig || path.join(os.tmpdir(), uniqueString()); // xdgConfig 获取配置文件夹路径,如果没有则使用临时文件夹路径 "C:\\Users\\admin\\.config"
const permissionError = 'You don\'t have access to this file.';
const mkdirOptions = {mode: 0o0700, recursive: true}; // 递归创建文件夹 0o0700 代表文件夹所有者可读可写可执行,其他人不可读不可写不可执行
const writeFileOptions = {mode: 0o0600}; // 创建文件  0o0600 代表文件所有者可读可写,其他人不可读不可写

/**
 * @param {string} id - The project ID.
 * @param {object} defaults - Default config.
 * @param {object} options - Options.
 * @param {boolean} options.globalConfigPath - Use a path within the user home directory.
 * @param {string} options.configPath - Use a custom path for the config file.
 */
export default class Configstore {
	constructor(id, defaults, options = {}) {
		// pathPrefix是一个路径前缀,如果options.globalConfigPath为true,则为id/config.json,否则为configstore/id.json
		const pathPrefix = options.globalConfigPath ?
			path.join(id, 'config.json') :
			path.join('configstore', `${id}.json`);
		// this._path是配置文件的路径 如果未指定options.configPath,则为configDirectory/pathPrefix
		// 例如:"C:\\Users\\admin\\.config\\" + "configstore\\configstore-test.json"
		this._path = options.configPath || path.join(configDirectory, pathPrefix);
		console.log('打印***this._path',this._path)
		// 如果defaults存在,则将defaults和this.all合并
		if (defaults) {
			this.all = {
				...defaults,
				...this.all
			};
		}
	}
	// all是一个getter/setter,用于获取/设置配置文件的内容
	get all() {
		try {
			return JSON.parse(fs.readFileSync(this._path, 'utf8'));
		} catch (error) {
			console.log('打印***err',error)
			// 如果文件夹不存在,则创建文件夹
			if (error.code === 'ENOENT') {
				return {};
			}

			// 提高权限错误的消息
			if (error.code === 'EACCES') {
				error.message = `${error.message}\n${permissionError}\n`;
			}

			// 如果遇到无效的JSON,则清空文件
			if (error.name === 'SyntaxError') {
				writeFileAtomic.sync(this._path, '', writeFileOptions);
				return {};
			}

			throw error;
		}
	}
	// all是一个getter/setter,用于获取/设置配置文件的内容
	set all(value) {
		try {
			// 确保文件夹存在,因为它可能已经被删除了
			fs.mkdirSync(path.dirname(this._path), mkdirOptions);
			// 写入文件
			writeFileAtomic.sync(this._path, JSON.stringify(value, undefined, '\t'), writeFileOptions);
		} catch (error) {
			// 提高权限错误的消息
			if (error.code === 'EACCES') {
				error.message = `${error.message}\n${permissionError}\n`;
			}

			throw error;
		}
	}
	// size是一个getter,用于获取配置文件的大小
	get size() {
		return Object.keys(this.all || {}).length;
	}
	// get是一个getter,用于获取配置文件的内容
	get(key) {
		return dotProp.get(this.all, key);
	}
	// set是一个setter,用于设置配置文件的内容
	set(key, value) {
		// 获取配置文件的内容
		const config = this.all;
		// 如果key是一个对象,则将key的所有属性设置到config中
		if (arguments.length === 1) {
			for (const k of Object.keys(key)) {
				dotProp.set(config, k, key[k]);
			}
		} else {
			// 否则将key和value设置到config中
			dotProp.set(config, key, value);
		}
		// 将config设置到配置文件中
		this.all = config;
	}
	// has是一个getter,用于判断配置文件是否存在key
	has(key) {
		return dotProp.has(this.all, key);
	}
	// delete是一个setter,用于删除配置文件的key
	delete(key) {
		const config = this.all;
		dotProp.delete(config, key);
		this.all = config;
	}
	// clear是一个setter,用于清空配置文件
	clear() {
		this.all = {};
	}
	// path是一个getter,用于获取配置文件的路径
	get path() {
		return this._path;
	}
}

整体流程如下:

  1. 首先,创建一个configstore实例,可以通过指定配置文件名和默认配置来初始化。

  2. 在应用程序中,可以使用configstore的API来读取、写入和修改配置数据。API包括读取配置项、写入配置项、删除配置项等。

  3. 在读取配置数据时,configstore会首先查找指定的配置项。如果不存在,则返回默认值(如果设置了)。如果没有设置默认值,则返回undefined。

  4. 在写入和修改配置数据时,configstore会将新的配置数据写入内部的配置对象中,并自动将数据保存到配置文件中。

  5. 配置文件存储在磁盘上的文件中,以JSON格式保存。在保存配置数据时,configstore将配置对象转换为JSON字符串,并将其写入文件中。

  6. 配置文件的存储路径由configstore自动管理,通常位于用户的home目录下的.config文件夹中。

流程图如下:

4. 总结

最后总结一下:

  • 学习了一些包工具如xdg-basedirdot-propwrite-file-atomic ,参考常用npm包使用
  • 存储的路径的学习
  • 使用getter、setter进行属性读写

每天一小点,加油 O^O!

相关推荐
hu_nil8 分钟前
Python第七周作业
java·前端·python
溜达哥25 分钟前
git commit 执行报错 sh: -/: invalid option
前端·javascript·git
江梦寻39 分钟前
最新Chrome与Selenium完美兼容指南(含驱动下载与配置)
前端·chrome·selenium·测试工具·edge·edge浏览器
Menior_43 分钟前
进程地址空间(比特课总结)
前端·chrome
kymjs张涛1 小时前
前沿技术周刊 2025-06-09
android·前端·ios
前端康师傅1 小时前
JavaScript 变量详解
前端·javascript
Sun_light1 小时前
队列:先进先出的线性数据结构及其应用
前端·javascript·算法
Data_Adventure2 小时前
如何在本地测试自己开发的 npm 包
前端·vue.js·svg
萌萌哒草头将军2 小时前
⚓️ Oxlint 1.0 版本发布,比 ESLint 快50 到 100 倍!🚀🚀🚀
前端·javascript·vue.js
ak啊2 小时前
WebGL入门教程:实现场景中相机的视角与位置移动
前端·webgl