菜单

Run 命令和脚本执行

相关源文件

Bun 中的命令和脚本执行系统处理三项核心职责:脚本执行、环境管理和进程创建。该系统使开发人员能够直接运行 JavaScript/TypeScript 文件(bun file.js)、执行 package.json 脚本(bun run start)以及在设置好适当的环境后创建外部进程。本文档详细介绍了涵盖脚本解析、环境变量管理、进程生命周期和执行流程的内部架构。

有关测试运行器的信息,请参阅 测试命令

概述

命令和脚本执行系统在 Bun 代码库的多个关键组件中实现。

脚本执行

  • RunCommand 结构体处理 package.json 脚本的解析和执行。
  • Run 结构体管理 JavaScript/TypeScript 文件的直接执行。
  • runPackageScriptForeground() 处理并执行包脚本。
  • runBinary() 创建外部可执行文件并传递参数。

环境管理

  • DotEnv.Loader 管理从 .env 文件加载环境变量。
  • env_loader.zig 提供全面的环境设置和配置。
  • 子进程的环境继承和修改。
  • 特殊的 npm 生命周期变量和特定于脚本的环境设置。

进程创建

  • bun.spawn 模块处理跨平台进程创建。
  • Process 结构体管理进程生命周期和退出处理。
  • 通过 findShell() 和系统 shell 发现进行 Shell 集成。
  • 信号处理和退出码传播。

来源: src/cli/run_command.zig262-411 src/bun_js.zig176-288

命令执行路径

直接执行 JavaScript/TypeScript 文件

运行 JavaScript 或 TypeScript 文件时,Bun 会初始化 JavaScript VM,设置运行时环境,并执行文件。此过程包括:

  1. 初始化 JavaScript 引擎 (JavaScriptCore)
  2. 设置模块加载器和转译器
  3. 配置环境变量
  4. 加载并执行入口文件
  5. 处理任何错误或未捕获的异常

来源: src/bun_js.zig176-288 src/bun_js.zig290-315

运行 package.json 脚本

运行 package.json 中定义的脚本时,Bun 会:

  1. 从 package.json 解析脚本
  2. 预处理脚本以替换包管理器命令
  3. 查找合适的 shell 来执行脚本
  4. 设置环境变量
  5. 在 shell 中执行脚本,或使用 Bun 内置的 shell 解释器执行脚本。
  6. 处理退出码和信号。

来源: src/cli/run_command.zig262-411

执行二进制文件

对于二进制执行(例如 node_modules/.bin 可执行文件),Bun 会:

  1. 解析可执行文件路径
  2. 设置环境
  3. 创建新进程来运行可执行文件
  4. 传递参数
  5. 处理退出码和信号。

在 Windows 上,还会额外处理 .bunx 文件格式,这是一种特殊的二进制可执行文件 shim。

来源: src/cli/run_command.zig432-547

环境管理

环境管理是处理环境变量加载、继承和所有执行上下文配置的关键组成部分。

环境变量加载

DotEnv.Loader 管理一个分层的环境变量系统:

  1. 系统环境变量:从父进程继承
  2. Dotenv 文件:按优先级顺序加载(.env.local 覆盖 .env 等)
  3. 脚本变量:npm_lifecycle_event, npm_lifecycle_script
  4. 特定于进程的变量:工作目录、PATH 修改

环境变量优先级

优先级来源示例
1(最高)进程参数NODE_ENV=production bun run build
2.env.local本地覆盖
3.env.{NODE_ENV}.local特定于环境的本地文件
4.env.{NODE_ENV}特定于环境的文件
5(最低).env基础环境

脚本环境设置

对于 package.json 脚本,系统会设置特定的环境变量。

来源: src/env_loader.zig22-317 src/cli/run_command.zig254-256 src/bun_js.zig254-269

进程创建

进程创建处理不同执行上下文中的子进程的创建和管理。

创建架构

创建系统根据目标使用不同的策略。

跨平台进程创建

系统处理平台在进程创建方面的差异。

平台方法实现
POSIXposix.fork() + exec()直接系统调用
WindowsCreateProcessWWin32 API,支持 UTF-16
所有bun.spawn.spawnProcess()统一接口

进程生命周期管理

每个创建的进程都通过 Process 结构体进行管理。

来源: src/bun.js/api/bun/process.zig144-217 src/cli/run_command.zig317-392

Shell 集成

命令执行需要找到并使用合适的 shell 来执行 package.json 脚本。

  1. 在 Unix 系统上,它会搜索 bash、sh 或 zsh。
  2. 在 Windows 上,它会使用 cmd.exe。
  3. 如果找不到 shell,它会回退到常见 shell 的硬编码路径。

脚本可以根据配置在系统 shell 中执行,也可以使用 Bun 的内置 shell 解释器执行。

来源: src/cli/run_command.zig62-101 src/cli/run_command.zig324-368

包管理器命令替换

为了提高兼容性和性能,Bun 会替换脚本中的包管理器命令。

  1. npm run 变为 bun run
  2. yarn run 变为 bun run
  3. pnpm run 变为 bun run
  4. npx 变为 bun x
  5. pnpx 变为 bun x

这样,为 npm/yarn/pnpm 编写的脚本无需修改即可与 Bun 配合使用。

来源: src/cli/run_command.zig140-258

二进制解析和执行

二进制执行涉及解析可执行文件路径,并使用适当的参数传递和环境继承来创建进程。

二进制解析过程

runBinary() 函数遵循系统的解析方法。

Windows 二进制 Shim 系统

在 Windows 上,Bun 使用复杂的 shim 系统来处理可执行文件解析。

组件目的位置
bun_shim_impl.exe通用 shim 可执行文件嵌入在 Bun 二进制文件中
.bunx 文件Shim 配置文件数据位于目标可执行文件旁边
BinLinkingShimShim 创建逻辑链接时生成

参数传递和环境

二进制执行会保留参数结构和环境。

  1. 参数数组:由传递的参数构建。
  2. 环境映射:通过 createNullDelimitedEnvMap() 创建。
  3. 工作目录:继承或显式设置。
  4. 标准 I/O:从父进程继承。

来源: src/cli/run_command.zig412-606 src/install/windows-shim/bun_shim_impl.zig1-42 src/install/windows-shim/BinLinkingShim.zig1-28

错误处理和退出码管理

该系统在所有执行路径中实现了全面的错误处理,保留了退出码和信号,以便与 CI/CD 正确集成。

退出码保留

退出码在整个执行链中被仔细保留。

信号处理

信号通过特定于平台的机制正确传播。

信号POSIX 处理Windows 处理
SIGINTGlobal.raiseIgnoringPanicHandler()转换为退出码
SIGTERM传播到父进程由进程终止处理
SIGKILL无法捕获立即终止

错误类别和响应

系统对不同错误类型进行分类和处理

进程退出处理

ProcessExitHandler 管理不同类型的子进程

  • Subprocess:JavaScript 子进程管理
  • LifecycleScriptSubprocess:包管理器生命周期脚本
  • ShellSubprocess:Shell 命令执行
  • ProcessHandle:通用进程管理

来源: src/cli/run_command.zig453-606 src/bun.js/api/bun/process.zig86-141 src/bun_js.zig453-468

与测试运行器的集成

运行命令在执行测试文件时与测试运行器协调。当一个文件被识别为测试文件时,它会被交给测试运行器执行,而不是直接运行。

这种交接发生在命令解析级别,CLI 根据提供的命令和参数决定是使用运行命令还是测试命令。

来源: src/cli.zig462-485

使用示例

以下是运行命令的一些常见用法模式

  1. 运行 JavaScript 文件: bun file.js
  2. 运行 TypeScript 文件: bun file.ts
  3. 运行 package.json 脚本: bun run start
  4. 运行二进制文件: bun run eslint
  5. 带参数运行: bun run test -- --verbose

运行命令的设计直观易懂,开发者从 Node.js、npm、yarn 或 pnpm 环境迁移过来能快速上手,同时提供了增强的性能和功能。

来源: src/cli/run_command.zig432-547 src/cli.zig462-485