当你在终端执行 npm run dev 时,背后会经过一系列文件调用和环境准备。下图和说明将完整还原这个过程的调用顺序:

1. npm run dev
   ↓
2. 读取 package.json 中的 "dev" 脚本,假设为 "vite"
   ↓
3. 在 node_modules/.bin 中找到 vite 可执行文件(指向 ../vite/bin/vite.js)
   ↓
4. 执行 node_modules/vite/bin/vite.js(CLI 入口)
   ↓
5. vite.js 解析 --debug/--profile 等参数,设置环境变量
   ↓
6. 动态导入 dist/node/cli.js(真正的 CLI 实现)
   ↓
7. cli.js 定义命令(使用 cac 库),注册 dev/build/preview 等
   ↓
8. 解析命令行参数,匹配到 dev 命令,执行其 action
   ↓
9. action 中动态导入 chunks/dep-xxx.js 中的 createServer
   ↓
10. 调用 createServer 加载用户配置(vite.config.js),创建开发服务器
    ↓
11. 启动 HTTP 服务器,输出访问地址

详细拆解每一步

1. npm run dev 触发
  • npm 读取当前目录下的 package.json,找到 scripts.dev 字段。
  • 假设值为 "vite",npm 会在项目 node_modules/.bin 目录下查找名为 vite 的可执行文件(这是 vite 包安装时生成的软链接,指向 vite/bin/vite.js)。
2. 执行 vite 命令
  • 由于 node_modules/.bin 被临时加入了 PATH,系统执行这个软链接,实际运行的是:

    bash

    node ./node_modules/vite/bin/vite.js
    
3. bin/vite.js 做什么?
  • 源码核心步骤:
    • 检测 --debug / -d 并设置 DEBUG 环境变量。
    • 检测 --profile 并启动 Node.js 内置的 CPU 性能分析器。
    • 记录启动时间戳 global.__vite_start_time
    • 动态导入 ../dist/node/cli.js(即构建后的 CLI 主模块)。
  • 为什么用动态 import?
    为了让 --profile 能够 wrap 整个启动过程,同时保证 ESM 模块正常加载。
4. dist/node/cli.js – 真正的命令行处理器
  • 这是 Vite 打包后的 ESM 文件(你提供的第三个代码块)。
  • 它使用 cac 库构建 CLI,定义了:
    • 全局选项:--config--base--logLevel--debug 等。
    • 命令:dev(别名 servedev)、buildoptimizepreview
  • cli.parse() 被调用时,会:
    • 解析 process.argv
    • 匹配出用户输入的命令(例如 vite 不带参数 → 默认 dev 命令)。
    • 执行对应命令的 action 函数。
5. dev 命令的 action
cli.command('[root]', 'start dev server')
  .action(async (root, options) => {
    // 过滤重复选项
    filterDuplicateOptions(options);
    // 动态导入 createServer
    const { createServer } = await import('./chunks/dep-281af434.js');
    const server = await createServer({ root, ...options, ... });
    await server.listen();
    // 输出启动信息,绑定快捷键...
  });
  • 懒加载createServer 从打包的 chunk 中导入,避免一开始就加载整个服务器逻辑。
  • createServer 内部会:
    • 合并命令行参数与配置文件(vite.config.js,通过 resolveConfig 加载)。
    • 创建 http / https 服务器。
    • 初始化中间件、插件容器、依赖预构建(optimizeDeps)。
    • 返回 ViteDevServer 实例。
6. 服务器启动
  • server.listen() 启动监听端口。
  • 控制台打印 VITE vx.x.x ready in xxx ms 以及本地/网络访问地址。
  • 绑定快捷键(如 r 重启服务器、p 启停 profiler、u 显示 URL 等)。

关键文件总结

文件路径 作用
package.json 定义 dev 脚本,触发 vite 命令
node_modules/.bin/vite 软链接,指向 vite/bin/vite.js
vite/bin/vite.js CLI 轻量入口:解析 profile/debug,动态加载 cli.js
vite/dist/node/cli.js CLI 主体:定义命令、选项、action
vite/dist/node/chunks/dep-xxx.js 核心功能 chunk:createServerbuild
vite/dist/node/constants.js 版本号等常量
vite.config.js(用户项目) 用户自定义配置,被 resolveConfig 加载

一句话总结调用顺序

npm run dev → 触发 vite 可执行文件 → bin/vite.js 预处理参数 → 动态导入 cli.js → 解析命令并匹配 dev action → action 中动态导入 createServer → 加载用户配置 → 启动开发服务器。

这个顺序体现了 Vite 的 懒加载 设计:只在真正需要时才加载对应模块,使得命令行响应极快,同时保留了性能分析等高级功能。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐