【源码共读】第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!

相关推荐
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html
秦jh_6 小时前
【Linux】多线程(概念,控制)
linux·运维·前端
蜗牛快跑2136 小时前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy6 小时前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js