rc 后缀是什么意思?(.babelrc、.vuerc、.prettierrc、.eslintrc、.npmrc...)

1,465

前端开发不可避免地会遇到各种 rc 后缀的文件,例如 .babelrc.vuerc.prettierrc.eslintrc.npmrc 等,大家不妨用下面的命令看下自己的电脑里面到底有多少个 rc 文件:

$ ls -l ~/.*rc
-rw-r--r--  1 keliq  staff  1768 12  3 21:52 /Users/keliq/.bashrc
-rw-r--r--  1 keliq  staff     8  2  4  2016 /Users/keliq/.cnpmrc
-rw-r--r--  1 keliq  staff   122  2 18  2020 /Users/keliq/.gemrc
-rw-------  1 keliq  staff  3257 11 10  2016 /Users/keliq/.linphonerc
-rw-r--r--  1 keliq  staff    68 10 27  2016 /Users/keliq/.mkshrc
-rw-------  1 keliq  staff   192 12  1 14:34 /Users/keliq/.npmrc
-rw-------  1 keliq  staff   612  6 28  2019 /Users/keliq/.opmrc
-rw-r--r--  1 keliq  staff   513 11  6  2017 /Users/keliq/.vimrc
-rw-r--r--  1 keliq  staff   120 12  2 10:09 /Users/keliq/.vuerc
-rw-r--r--  1 keliq  staff   386 12  7 23:31 /Users/keliq/.yarnrc
-rw-r--r--  1 keliq  staff  3468 10 19  2017 /Users/keliq/.zshrc

那么 rc 后缀是什么意思呢?为什么大家都喜欢用 .[xxx]rc 来保存配置?为什么有些是 JSON 格式、有些是 yaml 格式、甚至其他乱七八糟的格式?

rc 文件的由来

在 unix/linux 系统中,rc 是 run commands 的缩写,在早期程序启动的时候需要执行一系列的命令,于是就把这些命令保存到一个后缀为 .rc 的配置文件中,初始化的时候会执行这些命令,这个文件被称为 RUNCOM。这个习惯最早可追溯到 1965 年 CTSS 系统的启动脚本是 /etc/rc,后期就被沿袭下来成为一种命名约定,现在各大项目都用 rc 后缀作为运行时的配置文件,已经失去原有的保存可执行命令的含义了,因此很多人觉得 rc 被解释成 runtime configuration 更恰当一些。

rc 文件的格式

rc 文件其实没有约定的格式,各个程序自己解析即可,例如 json 格式就用下面的代码解析:

const fs = require('fs');
fs.readFile('~/.foorc', 'utf8', (err, data) => {
  if (err) throw new Error(err)
  console.log(JSON.parse(data))
})

当然 yaml 或其他格式也行,关键在于定义 rc 文件的程序自己如何解析。

rc 文件的位置

一般都是放在 ~/.[xxx]rc 中的,以 .vuerc 为例,源码里有这么一段代码:

async function configure (value, options) {
  const file = path.resolve(homedir, '.vuerc')
  const config = await fs.readJson(file)
}

很明显就是去 os.homedir() 中找,也就是 ~/.vuerc

rc 文件的作用

作用就是用于保存程序预设和用户自定义的配置,程序启动的时候要用,同样以 .vuerc 为例,在我电脑里面的内容为:

{
  "useTaobaoRegistry": false,
  "packageManager": "yarn",
  "latestVersion": "4.5.9",
  "lastChecked": 1606874972974
}

对应的源码是这样的:

const schema = createSchema(joi => joi.object().keys({
  latestVersion: joi.string().regex(/^\d+\.\d+\.\d+(-(alpha|beta|rc)\.\d+)?$/),
  lastChecked: joi.date().timestamp(),
  packageManager: joi.string().only(['yarn', 'npm', 'pnpm']),
  useTaobaoRegistry: joi.boolean(),
  presets: joi.object().pattern(/^/, presetSchema)
}))

那这些配置什么时候写入、什么时候使用呢?这里以 useTaobaoRegistry 为例,源码中是这样的:

module.exports = async function shouldUseTaobao (command) {
  let faster
  try {
    faster = await Promise.race([
      ping(defaultRegistry),
      ping(registries.taobao)
    ])
  } catch (e) {
    return save(false)
  }
  const { useTaobaoRegistry } = await inquirer.prompt([
    {
      name: 'useTaobaoRegistry',
      type: 'confirm',
      message: chalk.yellow(
        ` Your connection to the default ${command} registry seems to be slow.\n` +
          `   Use ${chalk.cyan(registries.taobao)} for faster installation?`
      )
    }
  ])
  return save(useTaobaoRegistry)
}

可以看到,vue 会通过 ping 来测试默认源和淘宝源哪个更快,很显然,如果用户在大陆的话,淘宝源更快,它就会询问用户是否切换为淘宝的源,如果用户同意,就写入到配置中。