Skip to content

configstore 存储

前言

在我们的项目中,我们经常会用到一些配置,比如:tokencookie用户名密码等等,这些配置我们一般会放在一个文件中,然后在项目中引入,但是这样做有一个问题,就是如果我们的项目是一个开源项目,那么这些配置就会暴露出来,这样就会有安全隐患,所以我们需要一个安全的地方来存储这些配置,这个时候就需要用到configstore这个包了。

安装

bash
npm install configstore

使用

js
const Configstore = require('configstore')
const pkg = require('./package.json')

// 创建一个configstore实例
const conf = new Configstore(pkg.name)

// 设置配置
conf.set('foo', 'bar')

// 获取配置
console.log(conf.get('foo')) // bar

// 删除配置
conf.delete('foo')

// 获取所有配置
console.log(conf.all) // {}

// 清空配置
conf.clear()

上面简单使用了下这个包,那么去看下这个包的源码,看看它是怎么实现的。

依赖

json
"dependencies": {
		"dot-prop": "^6.0.1",
		"graceful-fs": "^4.2.6",
		"unique-string": "^3.0.0",
		"write-file-atomic": "^3.0.3",
		"xdg-basedir": "^5.0.1"
	},
	"devDependencies": {
		"ava": "^3.15.0",
		"xo": "^0.38.2"
	},

看下所依赖的包都有什么作用

  • dot-prop:用来操作对象的属性
  • graceful-fs:用来操作文件
  • unique-string:生成唯一字符串
  • write-file-atomic:原子写入文件
  • xdg-basedir:获取用户目录
  • ava:测试框架
  • xo:代码检查

源码

js
import path from 'path'
import os from 'os'
import fs from 'graceful-fs'
import { xdgConfig } from 'xdg-basedir'
import writeFileAtomic from 'write-file-atomic'
import dotProp from 'dot-prop'
import uniqueString from 'unique-string'

// 获取用户目录
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 = {}) {
    const pathPrefix = options.globalConfigPath
      ? path.join(id, 'config.json')
      : path.join('configstore', `${id}.json`)

    this._path = options.configPath || path.join(configDirectory, pathPrefix)

    if (defaults) {
      this.all = {
        ...defaults,
        ...this.all,
      }
    }
  }
  // 获取配置文件所有内容
  get all() {
    try {
      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') {
        error.message = `${error.message}\n${permissionError}\n`
      }

      // Empty the file if it encounters invalid JSON
      if (error.name === 'SyntaxError') {
        writeFileAtomic.sync(this._path, '', writeFileOptions)
        return {}
      }

      throw error
    }
  }

  // 设置配置文件所有内容
  set all(value) {
    try {
      // Make sure the folder exists as it could have been deleted in the meantime
      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
    }
  }

  // 获取配置文件大小
  get size() {
    return Object.keys(this.all || {}).length
  }

  // 获取对应key的配置
  get(key) {
    return dotProp.get(this.all, key)
  }

  // 设置key,value
  set(key, value) {
    const config = this.all

    if (arguments.length === 1) {
      for (const k of Object.keys(key)) {
        dotProp.set(config, k, key[k])
      }
    } else {
      dotProp.set(config, key, value)
    }

    this.all = config
  }

  // 判断是否有key
  has(key) {
    return dotProp.has(this.all, key)
  }

  // 删除key
  delete(key) {
    const config = this.all
    dotProp.delete(config, key)
    this.all = config
  }

  // 清空配置
  clear() {
    this.all = {}
  }

  // 获取配置文件路径
  get path() {
    return this._path
  }
}

如有转载或 CV 的请标注本站原文地址