rc 后缀是什么意思

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

1
2
3
4
5
6
7
8
9
10
11
12
$ 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 格式就用下面的代码解析:

1
2
3
4
5
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 为例,源码里有这么一段代码:

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

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

rc 文件的作用

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

1
2
3
4
5
6
{
"useTaobaoRegistry": false,
"packageManager": "yarn",
"latestVersion": "4.5.9",
"lastChecked": 1606874972974
}

对应的源码是这样的:

1
2
3
4
5
6
7
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 为例,源码中是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 来测试默认源和淘宝源哪个更快,很显然,如果用户在大陆的话,淘宝源更快,它就会询问用户是否切换为淘宝的源,如果用户同意,就写入到配置中。