ToC
cac API
import { cac } from 'cac'
用于引入解析函数。
initial
const cli = cac('vite')
用于初始化一个参数解析器,接收一个可选参数,如果传入,则会在使用命令并附加 --hep
命令的时候将传入的参数替代命令原本的名称。比如我的 package.json 如下:
1{2 "bin": {3 "vite": "./test.js"4 }5}
test.js
如下:
1#!/usr/bin/env node2
3import { cac } from 'cac'4
5const cli = cac()6
7cli.help()8cli.parse()
那么在获取帮助的时候就会有这样的提示:
1vite2
3Usage:4 $ vite <command> [options]5
6Options:7 -h, --help Display this message
但如果我传入 test-vite
(const cli = cac('test-vite')
)则会变成:
1test-vite2
3Usage:4 $ test-vite <command> [options]5
6Options:7 -h, --help Display this message
参数主要是起帮助性的提示作用,不会影响功能。
command
创建一条命令,当在执行的时候,如果名称一致将匹配到它:
1cli.command('[root]', 'start dev server') // default command
在设置以后,使用帮助的时候也会打印出对应的提示信息:
1Commands:2 [root] start dev server
alias
给命令创建别名
1cli2 .alias('serve') // the command is called 'serve' in Vite's API3 .alias('dev') // alias to align with the script name
这样设置的话,就有了三种启动方式了:vite
、vite dev
、vite serve
。
option
给命令添加选项参数
1cli.option('--host [host]', `[string] specify hostname`)
action
在执行命令的回调函数,在执行的时候,会将所有收集到的参数依次传递:
1cli.action(async (root: string, options: BuildOptions & GlobalCLIOptions) => {})
help
为命令行的所有命令创建一个 --help
命令,同时添加一个 -h
的别名
parse
用于结束命令行的参数设置,只有在执行 cli.parse()
函数后,所有的设置才会被真正应用。
version
用于提示命令行当前的具体版本
1cli.version(VERSION)
devServer action
在了解了 cac 的主要 API 之后,我们先从 vite dev/server
开始吧。首先我们需要找到 cac 的 action 回调方法,其他的命令也是一样的,因为 action 方法是每个命令执行的起点,由这个回调函数来决定这个命令具体要做哪些事情。devServer 对 action 的处理为:
1const { createServer } = await import('./server') // -> packages/vite/src/node/index.ts2 try {3 // 创建一个 devServer 实例4 const server = await createServer({5 root, // 这里指的是调用 vite|vite dev|vite serve 时第一个位置的参数,比如: vite ./src6 base: options.base, // 可以通过 --base 设置起始路径:vite --base ./7 mode: options.mode, // 可以通过 --mode 设置是开发还是生产环境:vite --mode production8 configFile: options.config, // 可以通过 --config 来指定配置文件的文件路径:vite --config ./vite.config.js9 logLevel: options.logLevel, // 可以通过 --log-level 设置日志打印的级别,设置 warn 后,控制台就只会输出警告和错误信息,设置为错误就只会输出错误信息,而忽略警告和普通日志:vite --log-level error10 clearScreen: options.clearScreen, // 可以通过 --clear-screen 设置在产出新的日志时是否覆盖旧日志41 collapsed lines
11 optimizeDeps: { force: options.force }, // 可以通过 --force 设置是否强制优化某些依赖的构建12 server: cleanOptions(options) // 删掉所有可以解析的参数,将剩下的传递给 devServer13 })14 // 如果服务器未能成功创建15 if (!server.httpServer) {16 throw new Error('HTTP server not available')17 }18 // 启动服务器的监听19 await server.listen()20 // 获取到以启动服务器时的配置生成的日志打印器,用于打印服务器启动耗时及 url 信息21 // 如果 log-level 被设置成 silent、error、warn 的话,则启动耗时和 url 地址都不会在控制台打印22 const info = server.config.logger.info23
24 // @ts-ignore25 const viteStartTime = global.__vite_start_time ?? false // 获取服务启动前的运行时长26 const startupDurationString = viteStartTime27 ? colors.dim(28 `ready in ${colors.white(29 colors.bold(Math.ceil(performance.now() - viteStartTime))30 )} ms`31 )32 : ''33
34 info(35 `\n ${colors.green(36 `${colors.bold('VITE')} v${VERSION}`37 )} ${startupDurationString}\n`,38 // 如果在这之前触发过警告或错误打印,说明这中间有异常,则将启动完成的日志清除39 { clear: !server.config.logger.hasWarned }40 )41 // 打印 Local 和获取 Network 的数量并依次打印42 server.printUrls()43 } catch (e) {44 // 如果在创建服务器时出错则打印错误日志45 createLogger(options.logLevel).error(46 colors.red(`error when starting dev server:\n${e.stack}`),47 { error: e }48 )49 // 并结束这个进程50 process.exit(1)51 }
cleanOptions
1/**2 * removing global flags before passing as command specific sub-configs3 */4function cleanOptions<Options extends GlobalCLIOptions>(5 options: Options6): Omit<Options, keyof GlobalCLIOptions> {7 const ret = { ...options }8 delete ret['--']9 delete ret.c10 delete ret.config12 collapsed lines
11 delete ret.base12 delete ret.l13 delete ret.logLevel14 delete ret.clearScreen15 delete ret.d16 delete ret.debug17 delete ret.f18 delete ret.filter19 delete ret.m20 delete ret.mode21 return ret22}
以上.