前端开发不可避免地会遇到各种 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 来测试默认源和淘宝源哪个更快,很显然,如果用户在大陆的话,淘宝源更快,它就会询问用户是否切换为淘宝的源,如果用户同意,就写入到配置中。