一个 100MB 的 CLI 二进制文件

Anthropic 刚刚宣布,Claude Code 已经可以作为 原生构建 使用了。翻译一下:这意味着你可以直接下载一个可执行的二进制文件(通过 curl 安装),不需要再依赖 Node.js。

听起来是不是很棒?一个命令,没有额外依赖,后台还能自动更新。简直就是每个 CLI 工具的梦想。

但是有一个问题:这个二进制文件竟然有 100MB 的大小。

作为对比,git 的二进制文件大约只有 3MB,而 curl 则不到 1MB。就算以生成较大二进制文件著称的 Go,它的文件一般也很少超过 15-20MB。

那么,这 100MB 到底装了些什么?

不是 Rust,而是披了可执行文件外衣的 Bun

当我看到这个公告时,第一反应是:“一定是用 Rust 重写了。” 毕竟,要实现快速的原生二进制文件,而且不依赖运行时,Rust 是明显的选择。

但事实并非如此。

Claude Code 仍然是 TypeScript。Anthropic 使用了 bun build --compile 命令,将其打包成了可执行文件。

bun build --compile 的工作原理

神奇的命令是这样的:

bun build ./src/index.ts --compile --outfile claude

这个命令到底做了什么?分为三步来解释:

1. 打包

首先,Bun 作为一个打包工具,处理你的入口文件(比如 index.ts),解析所有的 import,并生成一个包含所有代码的单一 JavaScript 文件。在这个过程中,还会自动引入 node_modules 里的依赖,进行 tree-shaking 删除无用代码,并对结果进行压缩优化。

到这一步,其实和 esbuild 或 webpack 做的事情没什么不同。

2. 嵌入

有趣的部分来了。Bun 将生成的 JavaScript 打包文件 嵌入到一个可执行文件中,同时将整个 Bun 的运行时也一并嵌入。

最终生成的可执行文件结构如下(简化版):

┌─────────────────────────────────┐
│   Bun 运行时 (~95MB)            │
│   ├── JavaScriptCore 引擎        │
│   ├── 原生 API (fs, http)       │
│   ├── Zig 运行时                │
│   └── 静态 libc                 │
├─────────────────────────────────┤
│   你的代码打包 (~5MB)           │
│   └── JavaScript 压缩代码       │
└─────────────────────────────────┘

运行这个二进制文件时,Bun 的运行时会解压自身并执行其中的 JavaScript 代码。有点类似一个自解压的 ZIP 文件,不过是用于代码的。

3. 交叉编译

Bun 还可以为其他平台生成二进制文件:

bun build ./src/index.ts --compile --target=bun-linux-x64 --outfile claude-linux
bun build ./src/index.ts --compile --target=bun-darwin-arm64 --outfile claude-mac
bun build ./src/index.ts --compile --target=bun-windows-x64 --outfile claude.exe

你不需要在 Linux 系统上生成 Linux 的二进制文件。Bun 已经内置了每个平台预编译的运行时。

JavaScriptCore vs V8

Node.js 使用的是 Chrome 的 JavaScript 引擎 V8,而 Bun 使用的是 WebKit/Safari 的 JavaScriptCore (JSC)。

为什么这很重要?因为这两者差别很大:

对比项V8 (Node.js)JavaScriptCore (Bun)
启动时间~50 毫秒~5 毫秒
峰值性能非常高高
内存使用率较高较低
JIT 层级2 (Ignition → TurboFan)4 (LLInt → Baseline → DFG → FTL)

JSC 的启动速度更快,因为它有更多级别的 JIT 编译。从非常快速的解释器 (LLInt) 开始,一边执行一边在后台优化。而 V8 在开始执行前需要进行更多的初始化工作。

对于一个启动、执行完任务后立刻退出的命令行工具来说,这 45 毫秒的启动时间差异是关键点。而对于运行了数小时的服务器来说,差异就无关紧要了。

为什么用 Zig(而不是 Rust 或 C++)

Bun 主要用 Zig 语言编写,只有与 JavaScriptCore 交互的部分使用了少量 C++。

Bun 的创建者 Jarred Sumner 选择 Zig 的原因包括以下几点:

  1. 与 C 的互操作性:Zig 可以直接调用 C 代码,无需额外的开销或 FFI(外部函数接口)。JavaScriptCore 是用 C++ 编写的,Zig 能直接与其链接。

  2. 无垃圾回收的内存控制:和 Rust 类似,但语法更简洁,而且没有繁琐的 borrow checker。

  3. 轻松的跨平台编译:Zig 能从任意平台编译出适合其他平台的二进制文件。你无需在 Linux 机上为 Linux 编译。

  4. 相对较小的二进制文件:用 Zig 编写的“Hello World”程序大约 5KB,而 Go 编写的约为 2MB,Rust 编写的大约 300KB。

最终,Bun 的运行时实现了快速启动、低内存使用,并且可以作为一个单独的静态二进制文件分发。这种特性非常适合这种应用场景。

它不是什么

需要明确的是:这 并不是像 GraalVM 对 Java 或者 WASM 的那种 AOT(预编译)。

你的 TypeScript 代码 并不会被编译为 CPU 指令。它仍然由 JavaScriptCore 在运行时解释执行。唯一的变化是解释器和代码被一起打包了起来。

这个方式和以下做法相似:

  • Node.js 的 pkg 工具
  • Python 的 PyInstaller
  • 构建 Electron 应用的 electron-builder

这不是魔法。只是把运行时和代码放到一个单独的包里。所以这个二进制文件之所以会有 100MB 的大小,大部分原因在于 JavaScriptCore 和 Bun 的 API,而不是 Claude Code 的代码。

Anthropic 的收益是什么?

这是核心问题。因为这个改变根本不是为了你。

降低支持票数量

你知道 npm 会带来多少问题吗?权限问题、缓存损坏、Node 版本冲突、PATH 配置错误、神秘失踪的 800MB 的 node_modules…

每一个问题都可能导致一个用户提交技术支持请求。而每一个支持请求都意味着金钱和时间的投入。对于拥有数百万用户的 Claude Code 来说,减少与 npm 相关的问题是他们的主要动机。

无摩擦的自动更新

通过 npm,更新 Claude Code 的过程是:运行 npm update -g @anthropic/claude-code 命令。有的人会更新,但很多人不会。

而通过原生构建文件,更新可以在后台自动完成。Anthropic 对你运行的版本拥有完全的控制权。对于一个需要快速迭代并频繁修复错误的公司来说,这种控制是一笔巨大的财富。

可控的运行环境

当收到一个错误报告时,首先要问的是:“你用的是哪个版本的 Node?npm 版本是多少?操作系统是什么?”

使用原生构建后,这一切都消失了。每个人的执行环境完全一致。

可复现的错误 = 更容易解决的错误。

用户的收获是什么?

如果你没有安装 Node.js

显而易见的提升。之前你需要:

  1. 安装 Node.js
  2. 配置 PATH(如果没有自动完成)
  3. 安装 npm(尽管随 Node 一起安装,有时仍需更新)
  4. 运行 npm install -g @anthropic/claude-code
  5. 祈祷不会出现版本冲突

现在你只需要:

curl -fsSL https://claude.ai/install.sh | sh

对于非开发者 —— 产品经理、写作爱好者或设计师 —— 这个简化流程显然是巨大的差异。

如果你已经安装了 Node.js

坦白说,提升有限。你可能能避免一些偶尔出现的 npm 问题。自动更新非常方便。此外,原生构建版提供的原生语法高亮功能也是一个锦上添花的小优点。

但如果你已经通过 npm 安装并正常使用 Claude Code,这次的变化基本上对你的日常使用影响不大。

如何看待 100MB 的二进制大小

100MB 听起来或许很夸张。一个 CLI 工具而已。我们的前辈们用 4KB 内存编程,如今我们却要下载 100MB 的文件。

然而,实际来看:

  • VS Code ~300MB
  • Slack ~500MB
  • iOS SDK ~30GB
  • 一个典型的 Node.js 项目,其 node_modules 文件夹大小接近 500MB+

还有我的最爱:macOS Sequoia 包含 45GB 的壁纸。

四十五个 GB。全是壁纸。4K 下观赏的水母浮动、海浪拍岸、极光闪动,仅仅是为了让你的 iMac 有个漂亮的屏保。而这达到 Claude Code 体积的 450 倍。

Claude Code 可以成为一个能编写代码、执行命令和管理整个项目的 AI 助手。而苹果的壁纸带给你的,只是一些水母。

到 2026 年,当 1Gbps 的光纤和 1TB 的 SSD 成为标准配置时,100MB 根本就是可以忽略的体量。下载只需要几秒钟,保存下来后很快就会忘记它的存在。

是不是优雅的解决方案?不是。但在实践中,它真的重要吗?显然不太重要。甚至可以说,比那些水母更不重要。

你是否应该迁移?

如果你已经有可用的 npm 版本,那并不需要着急迁移。你可以通过现有的 npm 版本直接运行 claude install 来切换到原生构建版本。

如果你是第一次安装 Claude Code,请使用原生构建版本。这是官方推荐的选择,并且能减少潜在使用问题的概率。

如果你非常在意一个 100MB 的可执行文件占用你的磁盘空间,你也可以继续使用 npm。Anthropic 表示会同时保留两种安装方式,但显然原生构建是未来的方向。

不断重复的模式

其实这并不新鲜。这种模式反复在软件开发中上演:

  1. 起初你会依赖共享的依赖(DLL、系统库、npm 包)
  2. 然而,你面临多个版本和分发上的兼容性问题
  3. 最后你选择把一切都打包到一个“简单可用”的庞大包中

Docker 就是这样,Electron 也是这样,Bun 同样也是这样。

这是最优雅的解决方案吗?不是。但它几乎总是问题最少的。

有时候,工程学的目标不是找到最美的解决方案,而是那个能产生最少技术支持工单的方案。而年利润数十亿、用户数以百万计的 Anthropic 深谙其道。


相关文章:


本文原文为西班牙语,借助AI翻译。