返回

npm7.0源码分析(三)之npm config

前端

前面已经分析了npm如何启动,启动的核心就是拿到命令行参数,然后把这些参数处理成一个个option对象,再根据option对象来决定执行什么样的命令。

Option对象中有一部分是命令相关,比如install、uninstall、publish等等,还有一部分是命令相关的参数,比如-g表示全局安装,-S表示保存到项目依赖中,还有一些是命令行中没有的全局参数。npm命令行中没有的参数,但又想传递给执行的命令,可以采用如下方式:

npm config set [command-name] option-name value
npm config set install prefix /usr/local

把上述命令和如下命令进行对比一下:

npm install --prefix /usr/local

很明显,npm config set命令的功能和--prefix选项是相同的,npm config set命令的意义在于:可以在命令行中定义某个命令的参数,而这个参数可以在代码中进行读取。

当然,npm提供的不仅仅是set命令,还有getdeletelist等命令,下面我们来看看这些命令是如何实现的,通过这些命令的实现我们可以更深入地了解npm的执行机制。

config命令的入口

lib/config/index.js文件中,定义了如下函数:

/**
 * npm command: config
 *
 * @param {object} argv
 * @param {string} subcommand
 */
exports.config = function (argv, subcommand) {
  var subCmds = ['set', 'get', 'delete', 'edit', 'list']
  if (subCmds.indexOf(subcommand) === -1) {
    // config without subcommand
    return _usage()
  } else {
    return configCmd[subcommand](argv)
  }
}

函数exports.config是config命令的入口,当执行npm config命令时,这个函数会被调用。函数首先检查命令行中是否有子命令,子命令包括setgetdeleteeditlist。如果没有子命令,则调用_usage()函数输出帮助信息。如果有子命令,则调用对应的子命令函数。

config命令的子命令

lib/config/config.js文件中,定义了如下函数:

const config = exports = module.exports = {}

/**
 * npm config set
 *
 * @param {object} argv
 */
config.set = function (argv) {
  var sections = argv.sections
  var npm = loadRoot()
  var name = argv.name
  var value = argv.value

  argv.set = true
  config.processArgs(sections, npm, argv)
  config.save(argv.name, argv.value, npm)
}

/**
 * npm config get
 *
 * @param {object} argv
 */
config.get = function (argv) {
  var sections = argv.sections
  var npm = loadRoot()
  var name = argv.name

  config.processArgs(sections, npm, argv)
  var value = config.read(argv.name, npm)
  console.log(value)
}

/**
 * npm config delete
 *
 * @param {object} argv
 */
config.delete = function (argv) {
  var sections = argv.sections
  var npm = loadRoot()
  var name = argv.name

  config.processArgs(sections, npm, argv)
  config.remove(argv.name, npm)
}

/**
 * npm config edit
 *
 * @param {object} argv
 */
config.edit = function (argv) {
  var npm = loadRoot()
  var configPath = config.get(argv).config

  spawn(process.env.EDITOR, [configPath]).on('close', function (code) {
    if (code) {
      return npm.log.error('editor exited with error code', code)
    }

    npm.commands.rebuild(npm, [], function (er) {
      if (er) return npm.log.error('Error: rebuild failed', er)
      config.get(argv)
    })
  })
}

/**
 * npm config list
 *
 * @param {object} argv
 */
config.list = function (argv) {
  var npm = loadRoot()
  var sections = argv.sections
  var name = argv.name
  var scope = argv.scope

  config.processArgs(sections, npm, argv)
  return config.listConfig(argv, npm)
}

这些函数是config命令的子命令函数,每个函数对应一个子命令。

  • config.set函数是set子命令的函数,用于设置npm的配置参数。
  • config.get函数是get子命令的函数,用于获取npm的配置参数。
  • config.delete函数是delete子命令的函数,用于删除npm的配置参数。
  • config.edit函数是edit子命令的函数,用于编辑npm的配置文件。
  • config.list函数是list子命令的函数,用于列出npm的配置参数。

config命令的公共函数

lib/config/config.js文件中,还定义了一些公共函数,这些函数被config命令的子命令函数使用。

  • config.processArgs函数用于处理命令行参数。
  • config.save函数用于保存npm的配置参数。
  • config.read函数用于读取npm的配置参数。
  • config.remove函数用于删除npm的配置参数。
  • config.listConfig函数用于列出npm的配置参数。

config命令的实现原理

config命令的实现原理很简单,它首先调用config.processArgs函数处理命令行参数,然后根据不同的子命令调用不同的函数。

  • set子命令调用config.save函数保存npm的配置参数。
  • get子命令调用config.read函数读取npm的配置参数。
  • delete子命令调用config.remove函数删除npm的配置参数。
  • edit子命令调用spawn函数打开npm的配置文件。
  • list子命令调用config.listConfig函数列出npm的配置参数。

如何在代码中使用npm config API

npm config命令提供了丰富的API,我们可以