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

相关推荐
蟾宫曲3 小时前
在 Vue3 项目中实现计时器组件的使用(Vite+Vue3+Node+npm+Element-plus,附测试代码)
前端·npm·vue3·vite·element-plus·计时器
秋雨凉人心3 小时前
简单发布一个npm包
前端·javascript·webpack·npm·node.js
liuxin334455663 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
qq13267029403 小时前
运行Zr.Admin项目(前端)
前端·vue2·zradmin前端·zradmin vue·运行zradmin·vue2版本zradmin
魏时烟4 小时前
css文字折行以及双端对齐实现方式
前端·css
2401_882726485 小时前
低代码配置式组态软件-BY组态
前端·物联网·低代码·前端框架·编辑器·web
web130933203985 小时前
ctfshow-web入门-文件包含(web82-web86)条件竞争实现session会话文件包含
前端·github
胡西风_foxww5 小时前
【ES6复习笔记】迭代器(10)
前端·笔记·迭代器·es6·iterator
前端没钱5 小时前
探索 ES6 基础:开启 JavaScript 新篇章
前端·javascript·es6
m0_748255266 小时前
vue3导入excel并解析excel数据渲染到表格中,纯前端实现。
前端·excel