源码学习目录

1. 前言

1.1 环境

  1. 操作系统: macOS 11.5.2
  2. 浏览器: Chrome 94.0.4606.81
  3. configstore 6.0.0

    1.2 阅读该文章可以get以下知识点

  • 了解 configstore 作用和使用场景

    2. 开始

    2.1 index.js中的npm包

    1. import path from 'path';
    2. import os from 'os';
    3. // 更优雅的fs模块,对fs改进
    4. import fs from 'graceful-fs';
    5. // 获取用户配置路径 ~/.config文件夹
    6. import {xdgConfig} from 'xdg-basedir';
    7. // 写入文件
    8. import writeFileAtomic from 'write-file-atomic';
    9. // 通过'foo.bar'的方式来获取删除更新深层的对象,
    10. // dotProp.get({foo: {bar: 'unicorn'}}, 'foo.bar'); => 'unicorn'
    11. import dotProp from 'dot-prop';
    12. // 生成唯一字符串
    13. import uniqueString from 'unique-string';
    write-file-atomic
    graceful-fs
    xdg-basedir
    unique-string
    dot-prop

    2.2 index.js 源码

    ```javascript // config文件夹目录 const configDirectory = xdgConfig || path.join(os.tmpdir(), uniqueString()); // 无权限抛出 const permissionError = ‘You don\’t have access to this file.’; // 文件夹的配置,recursive支持递归, mode: 文件夹权限 const mkdirOptions = {mode: 0o0700, recursive: true}; // 写入权限 const writeFileOptions = {mode: 0o0600};

export default class Configstore { // id就是文件名,defaults是存入的数据默认值,第三个是配置项 constructor(id, defaults, options = {}) { // 如果传入了有全局文件路径,直接拼接路径 ${id}/config.json const pathPrefix = options.globalConfigPath ? path.join(id, ‘config.json’) : // 如果没配置,使用默认文件夹 configstore/${id}.json path.join(‘configstore’, ${id}.json);

  1. // 文件路径,可以直接配置也可以使用拼接默认的
  2. this._path = options.configPath || path.join(configDirectory, pathPrefix);
  3. // 传入默认值
  4. if (defaults) {
  5. this.all = {
  6. ...defaults,
  7. ...this.all
  8. };
  9. }
  10. }
  11. // class语法,get是监听取值,当this.all的时候,会执行里面的代码
  12. get all() {
  13. try {
  14. // 读取配置文件,json解析
  15. return JSON.parse(fs.readFileSync(this._path, 'utf8'));
  16. } catch (error) {
  17. // Create directory if it doesn't exist
  18. if (error.code === 'ENOENT') {
  19. return {};
  20. }
  21. // Improve the message of permission errors
  22. if (error.code === 'EACCES') {
  23. error.message = `${error.message}\n${permissionError}\n`;
  24. }
  25. // Empty the file if it encounters invalid JSON
  26. if (error.name === 'SyntaxError') {
  27. writeFileAtomic.sync(this._path, '', writeFileOptions);
  28. return {};
  29. }
  30. throw error;
  31. }
  32. }
  33. // 设置all
  34. set all(value) {
  35. try {
  36. // Make sure the folder exists as it could have been deleted in the meantime
  37. // 确保存在,可以创建文件
  38. fs.mkdirSync(path.dirname(this._path), mkdirOptions);
  39. // 写入,并格式化
  40. writeFileAtomic.sync(this._path, JSON.stringify(value, undefined, '\t'), writeFileOptions);
  41. } catch (error) {
  42. // Improve the message of permission errors, 没有文件写入权限
  43. if (error.code === 'EACCES') {
  44. error.message = `${error.message}\n${permissionError}\n`;
  45. }
  46. throw error;
  47. }
  48. }
  49. // 获取有多少key
  50. get size() {
  51. return Object.keys(this.all || {}).length;
  52. }
  53. // 获取key值,支持dot path的写法 => foo.bar.cc
  54. get(key) {
  55. return dotProp.get(this.all, key);
  56. }
  57. // 设置key值
  58. set(key, value) {
  59. const config = this.all;
  60. // 如果只有key一个参数,相当于直接更新
  61. if (arguments.length === 1) {
  62. for (const k of Object.keys(key)) {
  63. dotProp.set(config, k, key[k]);
  64. }
  65. } else {
  66. // 有key和value直接设置
  67. dotProp.set(config, key, value);
  68. }
  69. this.all = config;
  70. }
  71. // 判断是否有这个key
  72. has(key) {
  73. return dotProp.has(this.all, key);
  74. }
  75. // 删除某个key的值
  76. delete(key) {
  77. const config = this.all;
  78. dotProp.delete(config, key);
  79. this.all = config;
  80. }
  81. // 清空
  82. clear() {
  83. this.all = {};
  84. }
  85. // 获取配置文件路径
  86. get path() {
  87. return this._path;
  88. }

}

```

3. 总结

代码比较少只有100多行,主要有两点

  1. 将配置项通过文件读写,缓存到本地
  2. 操作对象的核心方法通过一个dot-prop的库来处理的

    4. 参考文档

  3. https://github.com/yeoman/configstore