1. 准备
● github.com/yeoman/conf…
● github1s.com/yeoman/conf…
1.1 学习目的
● 了解configstore是的什么,其作用和使用场景
1.2 准备工作
git clone https://github.com/yeoman/configstore.git
接着读index.js
2.初识configstore
Easily load and persist config without having to think about where and
how 轻松加载和持久化配置,而无需考虑位置和方式
2.1 下载
npm install configstore
2.2 使用
import Configstore from 'configstore';
//读取package.json文件
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
// 实例化配置存储实例
const config = new Configstore(packageJson.name, {foo: 'bar'});
// get方法获取配置
console.log(config.get('foo')); //=> 'bar'
// set方法设置配置
config.set('awesome', true);
console.log(config.get('awesome')); //=> true
// 设置嵌套属性
config.set('bar.baz', true);
console.log(config.get('bar')); //=> {baz: true}
// 删除属性
config.delete('awesome');
console.log(config.get('awesome')); //=> undefined
2.3 看看官网给的API
● Configstore(packageName,default?,options?)
packageName 包名 type:String
default 默认配置 type:Object
options type:Object
● 属性实例/方法构造函数
.set(ket,value) //设置一个项目
.set(object) // 设置多个项目/对象
.get(key) //获取
.has(key) //检查是否存在
.delete(key) //删除
.clear() //清除所有
.size // 获取项目数量
.path //获取配置文件的路径,可用于向用户显示配置文件所在的位置,或者更好的打开它
.all //将所有配置作为对象获取或将当前配置替换为对象:
config.all = {
hellol:'word
}
3.源码阅读
import path from 'path'; // path 主要用处处理文件路径(菜鸟教程)[https://www.runoob.com/nodejs/nodejs-path-module.html]
import os from 'os'; // os 模块提供了一些基本的系统操作函数
import fs from 'graceful-fs'; // 文件系统模块(菜鸟教程)[https://www.runoob.com/nodejs/nodejs-fs.html] graceful-fs 是fs的替代品,进行了各种改进
import {xdgConfig} from 'xdg-basedir';// 获取路径,该软件包适用于Linux。 您不应在macOS或Windows上使用XDG。
import writeFileAtomic from 'write-file-atomic';// fs.writeFile的扩展,使其操作原子化,并允许您设置所有权。
import dotProp from 'dot-prop'; // 帮助快速访问 使用点路径从嵌套对象中获取,设置或者删除属性
import uniqueString from 'unique-string';// 生成一个唯一的随机字符串
///os.tmpdir() 返回操作系统的默认临时文件夹
// 如果是linux,获取xdgConfig;
// 否则 os.tmpdir() 操作系统默认的临时文件的目录,uniqueString() 唯一字符串
// 获取目录
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}; // 定义常量默认值 写入文件
export default class Configstore {
constructor(id, defaults, options = {}) {
// path.join 作用是连接路径
// 检查options 是否有 全局默认的路径
// 设置文件前缀路径:
// 如果有 就创建一个 以id 为目录的,config.json 文件 `${id}/config.json`
// 如果没有 就创建一个 以configstore 为目录的,`${id}.json`文件 `configstore/${id}.json`
const pathPrefix = options.globalConfigPath ?
path.join(id, 'config.json') :
path.join('configstore', `${id}.json`);
// 最终能够找到存储在本地文件的路径
// options.configPath 可以理解为默认配置文件中的路径
this._path = options.configPath || path.join(configDirectory, pathPrefix);
//defaults 表示默认配置文件的内容吧
if (defaults) {
// 解构赋值,合并传入的内容和原有的内容 会触发下面all属性的set方法
this.all = {
...defaults,
...this.all
};
}
}
/**
* all 的 get方法
*/
get all() {
try {
//读取中path路径的本地文件
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') {
//permissionError 上方定义的常量 没有访问文件的权限
error.message = `${error.message}\n${permissionError}\n`;
}
// Empty the file if it encounters invalid JSON
//如果文件是无效的json,清空文件
if (error.name === 'SyntaxError') {
// writeFileOptions 上方定义的常量 写入文件
writeFileAtomic.sync(this._path, '', writeFileOptions);
return {};
}
// 抛出错误
throw error;
}
}
//all 的 set方法
set all(value) {
try {
// Make sure the folder exists as it could have been deleted in the meantime
//确保该文件夹存在,因为它可能同时被删除
/**
* fs.mkdirSync 创建文件 fs.mkdirSync(path, [mode])
* path 将创建的目录路径
* mode 目录权限(读写权限),默认0o777 八进制表示的,一共4位:
* 浏览器上 0o0700 == 0o777
* */
/**
* path.dirname 返回路径中代表文件夹的部分
* JSON.stringify(value, undefined, '\t')
* 使用空格缩进(菜鸟教程)[https://www.runoob.com/js/javascript-json-stringify.html]
*/
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;
}
}
//属性 size
// 为size属性定义了getter方法,通过 “实例.size”的方式读取size属性;
get size() {
// 获取配置文件对象,并且获取所有键的数组,然后返回长度
return Object.keys(this.all || {}).length;
}
// configstore的get方法,其实就是传入key返回对应的值
get(key) {
// 使用点路径从嵌套对象中获取
return dotProp.get(this.all, key);
}
set(key, value) {
// 读取配置对象给config
const config = this.all;
// 如果参数长度是1的话,那么只传了一个参数key,表示一个对象
// 那么将这个对象所有的键和值,给配置对象设置上 循环这个对象赋值到config对象(也就是this.all)上
if (arguments.length === 1) {
for (const k of Object.keys(key)) {
// 使用点路径从嵌套对象中设置
dotProp.set(config, k, key[k]);
}
} else {
// 普通的设置键和值 如果只传了一个参数(key),例如这个情况 config.set({foo: 'bar'})
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;
}
// 清空配置文件内容,通过给all属性设置值为空对象,将调用all的set方法,往文件里面写内容
clear() {
this.all = {};
}
// 属性path,获取文件路径path
// 为path属性定义了getter方法,通过 “实例.path”的方式读取path属性。
get path() {
return this._path;
}
}
4. 总结收获
graceful-fs
是node
模块fs
的增强版,xdg-basedir
用于获取XDG Base Directory
路径。write-file-atomic
这是node
的fs.writeFile
的一个扩展,它使其操作成为原子性的,并允许您设置所有权(文件的uid/gid)dot-prop
帮助快速访问 使用点路径从嵌套对象中获取,设置或者删除属性
5. Configstore类
- 构造函数主要做的是根据传入的
id
,设置文件的存储路径_path
; - 如果有默认的存取内容
defaults
,就去创建对应文件,写入默认内容;不存在默认内容时,文件暂时不会创建 - 对应的实例方法
set、get、delete、has
内部都是调用dot-prop
这个包的相关方法,只不过就是在set时可以传入单个对象参数,设置多个key/value
值 Configstore
类的核心主要是围绕实例属性all的处理,设置了all的存值函数和取值函数get all
取值函数主要做的是读取对应_path的内容,如果路径不存在或者文件内容不符合json格式,抛出对应的错误- set all存值函数主要是创建文件,写入内容,如果无写入权限,抛出对应的错误