学习Bun相关的知识

783 阅读28分钟

前言

跟着官网学习bun, 本文记录学习过程,供实时查阅。虽然 bun 和 node.js 很相似,但是也有很多不同的地方。现在主流的 vite, vue,Tarui, 等,都提供了用 bun 安装的方式。所以还是很值得学习探究的。

Bun的star数上升的很快,以下是Bun 与 Node.js 的GitHub的star数: image.png image.png

什么是Bun?

Bun 是 JavaScript 和 TypeScript 应用程序的一体化工具包。其核心是Bun运行时,这是一个快速的 JavaScript 运行时,旨在替代 Node.js 它用 Zig 编写,由 JavaScriptCore 提供支持,大大减少了启动时间和内存使用。

    bun run index.tsx        # 支持 ts 和 jsx

bun命令行工具还实现了测试运行器、脚本运行器、和 与 Node.js兼容的软件包管理器,所有这些实现都比现有工具快得多,并且可以在现有的Node.js项目中使用,几乎不需要更改。

    bun run start                        # 可以运行 start 脚本
    bun install <pkg>                    # 可以安装依赖包
    bun build ./index.tsc                # 可以构建项目到浏览器使用
    bun test                             # 可以运行测试
    bunx cowsay 'Hello World!'           # 可以执行包

什么是运行时?

JavaScript(或者更正式地说,ECMAScript) 只是编程语言的规范。任何人都可以编写一个JavaScript引擎,摄取有效的JavaScript程序并执行它。当今使用的两个最受欢迎的引擎是 V8(由谷歌开发) 和 JavaScriptCore(由苹果开发)。两者都是开源的。
浏览器
值得注意的是,浏览器附带了 JavaScript 运行时,这些运行时实现了一组特定的Web的API,这些API通过全局的 Window 对象公开。浏览器执行的任何 JavaScript 代码都可以使用这些API在当前网页的上下文中实现交互或动态行为。
Node.js
同样,Node.js是一个JavaScript运行时,可以在非浏览器环境中(如:服务器)中使用。除了执行读取/写入文件(node:fs)网络(node:net,node:http) 等 操作系统级任务的内置模块以外,Node.js 执行的 JavaScript 程序还可以访问一组特定的 Node.js的全局变量,如:Buffer,process 和 __dirname Node.js还实现了基于 CommonJS 的模块系统和解析算法,该算法早于 JavaScript 的本机模块系统。

Bun 被设计为 Node.js 的更快,更精简,更现代的替代品。

Bun 设计目标

Bun 从头开始设计,考虑到了今天的 JavaScript 生体系统。

  • 速度。Bun进程的启动速度比 Node.js 更快。
  • TypeScript 和 JSX 支持。您可以直接执行 .jsx.ts.tsx文件;Bun会将这些文件转换为 javascript。
  • ESM 和 CommonJS 兼容。Bun推荐使用ES模块,但同时也支持 CommonJS。
  • Web标准API。Bun实现了标准的 Web API, 如:fetchWebSocketReadableStream等。
  • Node.js兼容性。除了支持 Node 风格的 模块解析外,Bun 还旨在与内置的 Node.js 全局( (processBuffer) 和 (pathfshttp等) 完全兼容。这是一项持续的努力,尚未完成。

Bun不仅仅是一个运行时。长期目标是成为一个有凝聚力的基础设施工具包,用于使用 JavaScript/TypeScript构建应用程序,包括软件包管理器、传输器、捆绑器、脚本运行器、测试运行器等。

Bun的目标是完整的与Node.jsAPI兼容。大多数用于Node.js环境的API 或者 npm软件包等用法,跟Bun大部分兼容,使用方式差不多的;Bun与Node.jsv20兼容情况查看

安装 Installing

Linux & macOS:

curl -fsSL https://bun.sh/install | bash

Linux & macOS: 如果要安装指定版本 v1.1.6

curl -fsSL https://bun.sh/install | bash -s "bun-v1.1.6" 

Windows

Bun在Window上的安装条件:至少需要Windows 10版本1809,打开 Window PowerShell 执行如下命令(多尝试几次,成功后,配置要环境变量):

powershell -c "irm bun.sh/install.ps1 | iex"

Windows: 如果要安装指定版本 v1.1.6

iex "& {$(irm https://bun.sh/install.ps1)} -Version 1.1.6"

也支持 zip的安装方式

升级 Upgrading

bun upgrade

Homebrew users 用户: 使用 homebrew 有冲突的话,也可以尝试 brew upgrade bun

卸载 Uninstall

在 Linux & macOS 卸载:

 rm -rf ~/.bun                  # for macOS, Linux, and WSL

在 Windows 上卸载:

powershell -c ~\.bun\uninstall.ps1

快速入门 QuickStart

先来简单的感受一下 bun;创建一个quickstart目录,用bun初始化工程,简单的脚本配置,跑起来看看,感受一下;

创建项目

创建bun项目,有两种命令: bun init bun create ; 这边先使用 bun init 创建 bun 项目;运行 bun init 来创建一个项目。bun init 是一个交互式工具,只需按 enter 即可接受每个提示的默认答案。

以下是使用终端命令创建的,当然也可以使用手动创建项目的文件夹,然后在项目文件夹下执行 bun init 来初始化; image.png webstorm展示项目目录以及运行情况; image.png **入口文件 .ts 和 .js 的区别: 由于我们的 入口点(入口文件) 是 一个 *.ts文件,所以 bun 会为你 生成一个 tsconfig.json。 如果你使用的是普通的 JavaScript例:(*.js), 它将生成一个 jsconfig.json即 入口文件后缀是 *.ts 的话,就会生成 tsconfig.json, 入口文件后缀是 *.js 的话,就会生成 jsconfig.json image.png

创建脚本

Bun 还可以从 package.json 中的 scripts 添加脚本。

添加 start 脚本,方便快速可视化的运行。 image.png

Bun安装依赖包

如果使用 Bun的时候发现ts检查类型,有提示类型错误。可以尝试检查如下2个步骤:
①.使用命令 bun add -d @types/bun@types/bun安装为开发依赖项;
②.修改 tsconfig.json 的配置,添加内容到tsconfig.json中的compilerOptions中 ;

①.使用命令 bun add -d @types/bun@types/bun安装为开发依赖项;

@types/bun 是 Bun内置API的 TypeScript定义。这样就能够在 TypeScript文件中引用Bun全局,而不会在编辑器中看到错误。

bun add -d @types/bun

image.png ②.修改 tsconfig.json 的配置;将以下内容添加到tsconfig.json中的compilerOptions中:

{
  "compilerOptions": {
    "lib": ["ESNext"],
    "target": "ESNext",
    "module": "ESNext",
    "moduleDetection": "force",
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "noEmit": true,
  }
}

Bun 支持,顶级await, JSX 和 扩展 .ts 导入等内容。默认情况下 TypeScript不允许。 Bun推荐的 tsconfig.jsoncompilerOptions 配置, 这样就可以在不看不到TypeScript编辑器警告的情况下使用这些功能:

{
  "compilerOptions": {
    // Enable latest features
    "lib": ["ESNext"],
    "target": "ESNext",
    "module": "ESNext",
    "moduleDetection": "force",
    "jsx": "react-jsx",
    "allowJs": true,

    // Bundler mode
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "noEmit": true,

    // Best practices
    "strict": true,
    "skipLibCheck": true,
    "noFallthroughCasesInSwitch": true,

    // Some stricter flags
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noPropertyAccessFromIndexSignature": true
  }
}

创建简单的HTTP服务器

使用 Bun.serve({}) 来创建一个简单的 HTTP服务器,然后用浏览器打开。

image.png

如何创建快速Bun项目

创建 bun 模版项目,可以使用两种命令: bun init bun create ;以下说明这个两个命令的适用情况,以及执行命令发生了什么?

bun init

bun init 是 一种 使用交互式命令,快速创建 空的 Bun 项目 方式; 适用于 创建 一个 全新的 空的 Bun项目 模版;

bun init命令,创建过程如下:

可以按enter回车键,接受每个提示的默认答案,当然可以输入答案修改; image.png

也可以使用 bun init 创建命令,可以通过传递命令参数 -y--yes 标志,即命令: bun init -ybun init --yes 的方式,默认接受所有默认值的方式,快速创建空的Bun项目模板; image.png

bun init工作的过程:

使用 bun init命令创建空项目: iazk3-qyaln.gif 项目目录结构: image.png

执行 bun init 是如何工作的?
它创建:

  • 名称默认为当前目录名称的 package.json
  • tsconfig.json文件或jsconfig.json文件,取决于入口点是否是TypeScript文件;
  • 默认为index.ts的入口点,除非存在任何index.{tsx, jsx, js, mts, mjs}package.json指定modulemain字段;
  • 一个README.md文件;
  • 一个 bun.lockb bun 的 lock 文件; 最后,它运行bun install来安装@types/bun 依赖;

bun create

其实你可以不需要 bun create 就可以使用 bun , 你根本不需要任何配置。这个命令的存在是为了使开发变得更快,更容易。适用于创建本地模板、来自于npm的模板(从npm上下载的bun项目模板到磁盘)、来自于GitHub的模板(从GitHub上下载bun的项目到磁盘);

注意:

直接使用 例如: bun create my-bun-app 创建新的项目,bun会尝试从npm源上查找my-bun-app项目,不存在就会报错image.png

远程模板

使用 bun create(假设没有同名的本地模板的情况下)下载远程模板到本地磁盘,下载源主要来自于 npmGitHub;

从npm源下载(From npm)

使用 bun create 可以从 npm源 下载bun项目到磁盘。

命令格式如:bun create <template> [<destination>] 使用bun create下载 remix, 可以执行如下两个效果相同的命令:

bun create remix
# 或
bunx create-remix
  • 运行 bun create remix命令,过程: image.png
  • 运行 bun create remix后, 磁盘的工程目录结构: image.png

大家看官网的时候会发现:
svelte.dev官网因为bun几乎兼容node,虽然这项兼容工作还在不断的持续进行,这就意味着一般可以使用 npm createnpm initnpx, 都可以尝试使用 bun create 命令; image.png Vue官网Vue官网提供了bun create的方式,快速创建Vue模版工程: image.png Vite官网, Vite 也是提供了 bun create vite的方式; image.png

现在市场上主流框架 或库 大都可以使用 bun create 方式,来快速创建它的模版工程;

综上所述,以下我们以 Vue 和 Svelet 为例,使用 bun create 快速创建它的模版工程目录:
使用 bun create svelte@latest my-svelte-app ;创建一个使用最新 SvelteKit 模板: image.png

使用 bun create vue@latest my-vue-project; 创建一个使用最新 vue 模版的项目: image.png

从GitHub源下载(From Github)

bun create 可以将 GitHub repo(Github仓库) 的内容,下载到磁盘;这个过程可能会稍微久一点,下载的过程可能会由于网络等原因,在 bun install 的时候,有些依赖包会安装失败,失败的话重新install下。和 git clone 类似。但是 bun create 会自动 install;

命令格式如:

bun create <user>/<repo>
bun create github.com/<user>/<repo>

可选地指定目标文件夹的名称。如果没有指定目的地,将使用repo(仓库)协议名称。

bun create <user>/<repo> mydir
bun create github.com/<user>/<repo> mydir

演示使用 bun create github.com/<repo> 命令的过程: image.png image.png image.png

下载完成后的工程目录 和 Github仓库中的文件一致: image.png Bun将执行以下步骤:

  • 下载模板
  • 将所有模板文件复制到目标文件夹中
  • 使用bun install安装依赖项。
  • 初始化一个新的Git repo协议。使用--no-git标志选择退出。
  • 运行模板配置的start脚本(如果已定义)。

默认情况下,Bun不会覆盖任何现有文件。使用--force标志覆盖现有文件。

本地模板

从本地模板下载From a local template。与远程模板不同,使用本地模板运行bun create将删除整个目标文件夹(如果它已经存在)!小心点。

Bun的模板可以扩展到支持本地文件系统上定义的自定义模板。这些模板应该位于以下目录之一:

  • $HOME/.bun-create/<name>:全局模板
  • <project root>/.bun-create/<name>:特定于项目的模板

注意—您可以通过设置BUN_CREATE_DIR环境变量自定义全局模板路径。

要创建本地模板,请导航到$HOME/.bun-create,并创建一个具有所需模板名称的新目录。

cd $HOME/.bun-create
mkdir foo
cd foo

然后,在该目录中创建一个包含以下内容的package.json文件:

{
  "name": "foo"
}

您可以在文件系统的其他地方运行bun create foo,以验证Bun是否正确找到您的本地模板。

设置逻辑

您可以在本地模板package.json"bun-create"部分中指定安装前和安装后设置脚本。

{
  "name": "@bun-examples/simplereact",
  "version": "0.0.1",
  "main": "index.js",
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "bun-create": {
    "preinstall": "echo 'Installing...'", // a single command
    "postinstall": ["echo 'Done!'"], // an array of commands
    "start": "bun run echo 'Hello world!'"
  }
}

支持以下字段。其中每一个都可以对应一个字符串或字符串数组。命令数组将按顺序执行。

字段描述
postinstall安装依赖项后运行
preinstall在安装依赖项之前运行

克隆模板后,bun create将自动从package.json中删除"bun-create"部分,然后再将其写入目标文件夹。

bun create 命令标志

bun create 命令后面,可以带以下标志参数;例:bun create vue@latest --no-install;

标志描述
--force覆盖现有文件;
--no-install跳过安装 node_modules 和 任务;
--no-git不要初始化git存储库;
--open完成后启动并打开浏览器;

运行时 RunTime

bun run

bun命令可以被用来执行 JavaScript、TypeScript文件,package.json、scripts以及可执行包等。

Bun性能: Bun被设计为快速启动 和 快速运行。 Bun使用苹果为Safari开发的 JavaScriptCore 引擎,在大多数情况,启动和运行性能比 Node.js和基于Chromium的浏览器使用的引擎V8快。它的 transpiler 和 runtime 是用 Zig 编写的,Zig是一种现代的高性能语言,在Linux上,这转化为启动时间比Node.js快 4 倍。

运行一个文件

还记得吗? node 也可以执行一个文件,例:node index.js, bun 也可以运行一个文件,感觉 bun 会比 node 执行的快一点;

回忆一下node运行一个文件: image.png

bun 执行源文件,执行命令,如:bun run index.js
bun支持开箱即用的TypeScript 和 JSX每个文件在执行前都会由Bun的快速原生编辑器实时传输。 所以 bun 可以直接执行运行 js文件、 ts文件、tsx文件、 jsx 文件。 image.png 使用bun run命令,或者 可以直接 省略run关键字,它的行为是相同的;即例如: bun index.jsimage.png

--watch

需要在监视模式下运行文件,请使用 --watch 标志。**注意:这个 和 node 是不同的,使用 bun run 时,bun 后面立即放置标志; 因为命令末尾出现的标志将被忽略; **

正确语法: bun --watch run dev (✔️)
错误语法: bun run dev --watch (❌)
这就意味着,我们在监视模式下运行文件,是实时编译的; iShot_2024-05-26_21.44.03.gif

运行package.jsonscripts

npm run <scripts>yarn <scripts> 用法类似;我们可以在package.json中配置命名 scripts 要运行的命令 和 执行的命令行;然后使用 bun run <scripts>来执行这些脚本。

注意:如果命名的命令 和 Bun的内置命令名称冲突(和Bun的内置命令名称相同 install, dev, upgrade等), 内置命令优先; image.png

要查看可用的scripts脚本列表,请在没有任何参数的情况下运行bun runimage.png

bun run -

从 stdin 到管道代码, 为了方便起见,在使用 bun run - 时,所有代码都被视为支持JSX的TypeScript。

  • bun run - 运行您从 stdin 读取 JavaScript、TypeScript、TSX或JSX,并执行它,而无需写入临时文件。 image.png

  • 还可以使用 bun run - 将文件重定向到Bun中。例如,像运行.ts文件一样运行.js文件;即 可以通过管道,将内容写入到文件中并输出; iShot_2024-05-27_00.08.14.gif

bun run --smol

在内存受限的环境中,使用--smol标志,能减少内存使用;这样会导致垃圾回收器更频繁地运行,这可能会减慢执行速度,然而,它在内存有限的环境中非常有用。Bun根据可用内存(考虑C组 和 其他内存限制)自动调整垃圾回收器的堆大小,有和没有--smol标志,着对于堆大小增长更慢的情况非常有用。

命令格式:bun --smol run index.tsx

对文件类型的支持

Bun 原生支持开箱即用的TypeScript。所有文件在执行前都有Bun的快速原生转换器进行实时转换·(Bun的内部编译器在执行前的时候会将 .jsx, .tsx, .ts文件转换成普通的 js.)。与其他构建工具类似,Bun不执行类型检查;类型检查受到 tsconfig.json配置文件的影响。

  1. Bun支持.js文件、.jsx文件、.ts文件、.tsx文件类型,可以直接运行或者执行; image.png
  2. 支持 文本文件 可以作为字符串导入; image.png
  3. 支持 JSON 和 TOML 文件 可以直接从源文件导入。内容将作为 JavaScript对象载入 并返回; image.png
  4. (实验性功能) Bun 对 WASI(WebAssembly系统接口) 有实验性的执行。使用 Bun运行 .wasm 二进制文件; image.png
  5. SQLite 支持将 sqlite 数据库直接导入到你的代码中,Bun 将自动加载数据库 并 返回 Database 对象; image.png
  6. 支持配置 自定义 loaders ,配置插件,扩展对其他类型文件的支持;

对TypeScript的支持

Bun 可以直接执行 .ts.tsx文件,就像执行 普通的JavaScript一样,无需额外的配置。如果 我们 import .ts.tsx文件(或者export这些文件变成npm模块),Bun在内部会将这些转换为JavaScript。然后执行。

Bun会读取 tsconfig.json 的规则,以确定如何转换。

  1. 在解析模块的时候,Bun在运行时,遵守的是 tsconfig.json 中定义的 compilerOptionspaths 的 路径映射; image.png
  2. Bun 将使用 baseUrl 来解析模块路径; image.png
  3. Bun还能正确的解析,从 data.ts中,导入的问题;
    data.ts
    // data.ts
    export const foo = "Hello world!"
    
    index.ts
    import { foo } from "data";
    console.log(foo); // => "Hello world!"
    

对 JSX 的支持

Bun支持开箱即用的.jsx.tsx文件。 Bun的内部编译器在执行前会将 JSX语法转换为普通的 JavaScript;

Bun会读取 tsconfig.jsonjsconfig.json 配置文件,以便确定如何在内部执行 JSX 的转换,为了避免使用其中任何一个,也可以在bunfig.tom中定义;

bunfig.toml

bunfig.tomBun 的配置文件,Bun的行为可以使用 bunfig.toml 进行配置。一般来说,Bun依靠package.jsontsconfig.json 等预先存在的配置文件来配置其行为。bunfig.toml仅用于配置Bun的特定的东西。这个文件是可选的。即使没有配置它,Bun也是开箱即用的。

本地配置

一般来说,建议将 bunfig.toml文件 与 你的 package.json文件 一起添加到项目的根目录中的;

全局配置

要全局配置Bun, 可以在以下路径之一创建 .bunfig.toml文件:

全局配置可以在以下路径之一配置 创建 .bunfig.toml 文件:

  • $HOME/.bunfig.toml
  • $XDG_CONFIG_HOME/.bunfig.toml

如果Bun检查到,全局和本地都有bunfig, 会将它们 浅合并,局部的覆盖全局。

环境变量

一般来说,使用Bun,你不再需要dotenvdotenv-expand, 因为Bun会自动读取 .env 文件,并提供以编程的方式读取 和 写入环境变量的方法。此外,Bun运行时行为的某些方面可以使用Bun特定的环境变量进行配置。

读取环境变量

访问当前环境变量有如下3种方式:

  1. process.env, 使用方式,例:process.env.FOO;
  2. import.meta.env, 使用方式,例:import.meta.env.FOO;
  3. Bun.env, 使用方式,例:Bun.env.FOO;

image.png

使用 bun --print process.env 命令, 可以将所有当前设置的环境变量打印到命令行;

使用 bun --print Bun.envbun --print import.meat.env 目前也是可以打印的; image.png

注意:

  1. 目前可以打印 .env,.env.local,.env.development中的环境变量,自定义.env.XX 好像访问不了环境变量。
  2. 如.env文件 设置设置了同名的环境变量名,会取值 Bun读取的优先级顺序高的.env文件;Bun读取.env文件的优先级,在设置环境变量章节有说明; image.png

设置环境变量

一般.env类型的文件,都是创建于项目的根目录下的;

Bun会自动以下文件,按照读取的优先级的递增顺序 列出:

  • .env :优先级最低
  • .env.production.env.development.env.test(取决于NODE_ENV的值)
        # 即需要在该.env文件头位置定义 NODE_ENV=development, 否则环境变量可能无法被访问到;
        # env.development
        NODE_ENV=development
        FOO=xxx
    
  • .env.local :优先级最高

创建.env文件:
.env,.env.production,.env.development,.env.test,.env.local 都是在项目根目录下创建的image.png

设置如何设置环境变量

  1. 环境变量一般是以大写的字母组成变量; 格式如:KEY=value; 常规定义value不需要带引号;value的数据类型是 string ;

        FOO=hello
        BAR=world
    
  2. Bun支持使用双引号,单引号,反引号 定义环境变量的值,适用于值不连贯带空格的字符串:

        FOO='hello'
        FOO="hello"
        FOO=`hello`
        # 更适用于 不连贯有空格的的字符串
        BAR='hello word hello bun'
    
  3. 环境变量会自动扩展,即:可以在环境变量中可以使用$来引用之前定义的环境变量:

        FOO=world
        # 使用 $ 来引用上面的 FOO环境变量,所以 BAR 的值是 helloworld
        BAR=hello$FOO
    

    使用$来引用之前定义的环境变量,这对于构造连接字符串和复合值很有用:

        SERVER_HOST=127.0.0.1
        SERVER_PORT=8080
        # 使用$引用上面的环境变量,所以 SERVER_URL的值是 http://127.0.0.1:8080
        SERVER_URL=http://$SERVER_HOST:$SERVER_PORT
    
  4. 因为$被用于引用之前定义的环境变量,那么要输出$可以通过使用反斜杠来转义$,即:使用反斜杠转义可以输出$:

        FOO=world
        # 使用转义符 转义 $, BAR的值是 “hello$FOO”
        BAR=hello\$FOO
    
  5. 还可以通过将属性分配给process.env的方式,来设置环境变量; 例: process.env.KEY = value 来设置环境变量:

        process.env.FOO = "hello";
    
  6. 在bun运行的时候,可以通过手动指定.env文件的方式:

Bun 支持--env-file来覆盖要加载的特定的.env文件。在bun的运行时或者运行 package.json脚本时,可以使用--env-file的方式,来指定要运行的 .env文件

直接使用bun命令,在终端运行时指定--env-file:
在项目根目录下创建.env.a,.env.b 并设置FOO的值,然后在index.ts中使用process.env.FOO 输出值,在终端使用命令运行; .bash bun --env-file=.env.b index.ts # 或 bun --env-file=.env.b run index.ts image.png

--env-file写到package.json中,做成脚本命令,然后在终端运行脚本命令:
package.json中的scripts下配置 脚本命令的方式,然后在项目根目录下的终端运行脚本命令: 在 package.json 中的 scripts 配置 start脚本命令时,指定--env-file

    {
      "name": "quickstart",
      "module": "index.ts",
      "type": "module",
      "bin": {
        "my-cli": "dist/index.js"
      },
      "scripts": {
        "clear": "rm -rf dist && echo 'Done!'",
        "start": "bun --watch --env-file=.env.abc --env-file=.env.def run index.ts",
        "build": "bun build ./index.ts --outdir ./build"
      },
      "devDependencies": {
        "@types/bun": "latest"
      },
      "peerDependencies": {
        "typescript": "^5.0.0"
      }
    }

然后在项目根目录下的终端运行 bun run start: image.png

在编辑器中使用有类似.env files support插件,可以辅助.env文件中环境变量的编写:
在代码编辑器中,以 webstorm 为例,可以下载插件 .env files support 来辅助或规范.env 的编写; image.png

TypeScript中配置环境变量

在 TypeScript 中,来自于 process.env的所有属性的类型都是string | undefined

为了保持自动推导编译,我们将告诉TypeScript将变量视为非可选的字符串,我们将使用接口合并方式,进行如下配置定义:

    declare module "bun" {
      interface Env {
        AWESOME: string;
      }
    }

这样我们就能在全局使用 AWESOME 属性。可以将属性添加到 process.envBun.env:

    process.env.AWESOME; // => string

Bun的部分环境变量说明

Bun也有自身自带的环境变量,我们可以配置它的行为; Bun会自动读取这些环境变量;

这是Bun的部分环境变量的行为说明描述,如下:

环境变量名称描述
BUN_CONFIG_MAX_HTTP_REQUESTS控制获取和bun install发送的并发HTTP请求的最大数量。默认为256。如果您遇到速率限制或连接问题,您可以减少这个数字。
BUN_CONFIG_NO_CLEAR_TERMINAL_ON_RELOAD如果BUN_CONFIG_NO_CLEAR_TERMINAL_ON_RELOAD=1,那么bun --watch在重新加载时不会清除控制台
TMPDIR在 bundling或其他操作期间, Bun可能会需要一个目录来存储临时资源。如果未设置,默认为特定于平台的临时目录:Linux上的/tmp,macOS上的/private/tmp
......

Bun的API

Web API


作为包管理器的使用

bun install

bun install:安装项目的所有依赖项。能使用 npm install的地方,就可以使用bun install安装依赖。而且 bun install安装速度更快, 安装速度几乎是npm的25倍; image.png

运行 bun install工作过程:

  • 安装所有dependencies(生产依赖)、devDependencies(开发依赖)和optionalDependencies(可选依赖)。默认情况下,Bun将安装peerDependencies(特定依赖:与主应用的版本有关联);
  • 在适当的时候运行项目的{pre|post}install{pre|post}prepare脚本。出于安全原因 Bun不执行已安装依赖项的生命周期脚本;
  • 在项目根目录下将项目中的lockfile写入到bun.lockb,(项目根目录下生成bun.lockb);
  1. bun install的日志控制,有两个标志--verbose(详细的debug模式,安装情况的日志输出) 和 --silent(静默安装,没有日志输出);

        # --verbose 是 详细的debug模式,有日志输出
        bun install --verbose
        # --silent 是 静默模式,没有日志输出
        bun install --silent
    

    bun install --verbos: 有详细日志输出: image.png

    bun install --silent: 没有日志输出: image.png

  2. bun install: Bun默认不会执行被安装package中的scripts中的生命周期钩子,需要告诉Bun允许特定的package的生命周期脚本,请在package.json中将 包 添加到 trustedDependencies

与其他npm不同,Bun不会为已安装的依赖项执行任意的生命周期脚本,即,Bun默认不会执行被安装package中的scripts中的生命周期钩子,如postinstall。 执行任意脚本代表着潜在的安全风险。要告诉Bun允许特定的package的生命周期脚本,请在package.json中将 包 添加到 trustedDependencies

看着很难理解,我们先来学习下npm包的生命周期,各个阶段执行npm生命周期脚本以及含义?

npm script 的生命周期:

  • preinstall:在软件包安装开始之前触发。
  • postinstall:在安装软件包后立即触发。
  • preuninstall:在卸载软件包之前触发。
  • postuninstall:卸载软件包后触发。
  • prepare:在两种情况下触发:在本地安装软件包后(而不是通过注册表)和软件包打包和发布之前(例如,在npm publishnpm pack期间)。

npm scripts是写在 package.json中的 scripts; 当该package在被安装之前或之后,被卸载之前或者之后会触发执行对应的生命周期,并执行对应动作: image.png 案例说明:
我们新建个项目,使用 my-trusted-test (这个包已设置了对应生命周期钩子和输出日志),我们使用 npm install 加上命令标志(--foreground-scripts)来查看脚本执行情况和输出日志,观察下安装过程: image.png npm install 时 会执行scripts 中的生命周期,这个是非常危险的。这个就意味着可以利用这个特性,在安装依赖包的时候,进行访问用户文件,未授权的资源或者下载安装其他恶意软件,比如进行,例:cd xx ,rm -rf 等操作;
禁止执行scripts生命周期,可以在 install 的时候,添加标志,例如,npm install --ignore-scripts 你的依赖包,可以在项目的 .npmrc 中全局配置 ignore-scripts=true

  1. Bun 支持package.json中的 workspaces;

    {
      "name": "my-app",
      "version": "1.0.0",
      "workspaces": ["packages/*"],
      "dependencies": {
        "preact": "^10.5.13"
      }
    }
    
  2. Bun 在 package.json中,支持npm的overrides和Yarn的resolutions,指定元依赖性版本范围的机制,即 依赖项的依赖。

    {
      "name": "my-app",
      "dependencies": {
        "foo": "^2.0.0"
      },
      "overrides": {
        "bar": "~4.4.0"
      }
    }
    
  3. Bun install 安装模式, 全局安装: -g/--global, 以生产模式安装(即没有devDependenciesoptionalDependencies): --production;

    bun install --global cowsay
    # or
    bun install -g cowsay
    
    bun install --production
    

    对于可重现的安装,可以使用--frozen-lockfile。这将安装锁文件中指定的每个软件包的确切版本。如果你的package.json不同意bun.lockb,Bun将退出并出错。锁文件将不会更新。

    bun install --frozen-lockfile
    

    进行试运行安装,查看需要的安装的依赖;(实际上不会安装任何东西),需要在 bun init 的项目中使用,需要配置Scripts中的install: image.png 非npm依赖项的安装,Bun支持从 Git、GitHub 和 本地或者远程,安装依赖项目; image.png image.png

  4. bun install的默认行为可以在 bunfig.toml中配置; 具体的行为配置可以参考 bunfig.toml

    [install]
    
    # whether to install optionalDependencies
    optional = true
    
    # whether to install devDependencies
    dev = true
    
    # whether to install peerDependencies
    peer = true
    
    # equivalent to `--production` flag
    production = false
    
    # equivalent to `--frozen-lockfile` flag
    frozenLockfile = false
    
    # equivalent to `--dry-run` flag
    dryRun = false
    
    # equivalent to `--concurrent-scripts` flag
    concurrentScripts = 16 # (cpu count or GOMAXPROCS) x2
    

    image.png

  5. CI/CD的 pipeline 流水线配置,使用官方oven-sh/setup-bun操作 bun 的 install,配置CI/CD的流水线;

    name: bun-types
    jobs:
      build:
        name: build-app
        runs-on: ubuntu-latest
        steps:
          - name: Checkout repo
            uses: actions/checkout@v4
          - name: Install bun
            uses: oven-sh/setup-bun@v1
          - name: Install dependencies
            run: bun install
          - name: Build app
            run: bun run build
    
    

bun add

添加指定包(下载指定的依赖包)可以指定依赖包,版本范围,可以添加为dev依赖项,可选依赖等

  1. 下载添加指定的依赖包
    bun add preact
    
  2. 指定版本,版本范围或者指定标识:
    bun add zod@3.20.0
    bun add zod@^3.0.0
    bun add zod@latest
    
  3. --dev,-d,-D,--development: 将依赖包添加为 dev依赖项(package.json下的 "devDependencies" 项):

    增加 --development, 或 -d--dev-D;

    bun add --dev @types/react
    bun add -d @types/react
    
  4. --optional: 将依赖包添加为 可选依赖项(package.json下的 "optionalDependencies" 项):
    bun add --optional lodash
    
  5. --exact, -E: 添加固定版本的依赖包,
    bun add react --exact
    bun add react -E
    
    {
      "dependencies": {
        // without --exact 添加不固定的依赖包
        "react": "^18.2.0", // this matches >= 18.2.0 < 19.0.0
    
        // with --exact 添加固定版本的依赖包
        "react": "18.2.0" // this matches only 18.2.0 exactly
      }
    }
    
  6. --global,-g: 安装全局依赖包,这不会修改你当前项目的package.json。这通常用于安装命令行工具。
    bun add --global cowsay
    cowsay "Bun!"
    
  7. bun add 也可以 从 git仓库添加依赖包:
    bun add git@github.com:moment/moment.git
    
  8. bun add的时候不会执行任意包的 Scripts的生命周期,要执行指定依赖包的生命周期,需要在 package.json 中将依赖包添加到 trustedDependencies;
    例: 要添加 my-trusted-test并执行该依赖包的Scripts生命周期,需要在trustedDependencies中添加该依赖包:
    {
      "name": "my-app",
      "version": "1.0.0",
      "trustedDependencies": ["my-trusted-test"]
    }
    

bun remove

删除移除依赖包

bun remove ts-node

bun update

更新依赖包(依赖项)

  1. 将所有依赖项更新到最新版本;
    bun update
    
  2. 将指定的依赖包更新到最新版本;
    bun update [依赖包名称]
    
  3. --latest: 要更新到最新版本,无论它是否与当前版本范围兼容,就使用--latest标志:
    bun update --latest
    
    例:我们现在的package.json是如下的:
    {
       "dependencies": {
         "react": "^17.0.2"
       }
     }
    
    使用 bun update 将更新到与 17.x 匹配的版本。
    使用 bun update --latest 将更新到与 18.x 或更高版本匹配的版本。

bun pm

bun pm提供了一些命令组,它是实用的查看命令程序,用于查看Bun的软件包相关的命令;

  1. bun pm bin: 查看本地项目的bin目录路径,要在本地项目的根目录下运行; image.png
  2. bun pm bin -g: 查看全局bin目录的路径; image.png
  3. bun pm ls: 查看当前项目中已安装的依赖项及其它们的解析版本,不包括其他依赖项;
  4. bun pm ls --all: 查看所有已安装的依赖项,包含 nth-order 的dependencies; image.png
  5. bun pm cache: 查看 Bun 的全局模块缓存的路径;要在当前项目中运行;
  6. bun pm cache rm: 清除 Bun 的全局模块缓存;要在当前项目中运行; image.png 当然了。全局缓存,也可以通过配置文件bunfig.toml,进行配置它的行为方式;一般从下载源下载的所有软件包都会存储在~/.bun/install/cache的全局缓存中;
    image.png 也可以在全局配置中bunfig.toml配置缓存行为方式: image.png

bun link

bun link 的作用 和 npm link 类似,可以 在本地目录中使用 bun link 将当前包 注册为 "可链接" 包,就是将本地包注册做成 软链接(快捷方式),做成 本地全局包,这样可以在本地的其他项目中,使用 bun link xxx,将这个包链接到本地的其他项目, 也就是说在本地的其他项目的 node_modules 中创建了一个软链接,链接到本地这个bun link的可链接的包。这样就可以很方便的本地调试一些封装的库sdk等;

简单演示下 bun link的作用,示例: ①.首先我们使用bun init创建名称为cool-pkg的项目;然后在index.ts中导出一个求和函数;
image.png ②.在项目cool-pkg根目录下,运行bun link将当前项目注册成“可链接”包
image.png ③.现在可以使用 bun link cool-pkg将这个包,链接到其他项目中(例:my-app项目);这会在其他项目中的node_modules目录中创建一个符号链接,执行本地目录。
image.png ④.可以直接在其他项目中(my-app),使用或者引入 可链接包(cool-pkg包)中导出的函数
image.png ⑤.在使用可链接包bun link cool-pkg时,也可以通过添加 --save标志,将cool-pkg添加到应用程序的package.jsondependencies字段中,该link符号告诉Bun从注册的本地目录加载,而不是从npm安装; image.png

WorkSpaces(工作区)

Bun支持package.json中的workspacesworkspaces使得将复杂的软件作为由几个的独立的包,组成的单个包来开发变得容易;基于workspaces的特性,被常用于构建monorepo类型(单体仓库)的项目;

workspaces的几个优点:

  • 代码可以分为逻辑部分。如果一个包依赖于另一包,你可以简单地将其作为依赖项添加到package.json中。如果软件包b依赖于abun install会将你的本地包package/a目录安装到node_modules而不是从npm下载源下载。
  • 依赖项可以重复使用。如果ab共享一个共同的依赖项,它将被带到根node_modules目录。这就大大的减少了冗余磁盘的使用。并最大限度的减少了与同时安装多个版本的软件包相关的 “依赖地狱”问题。
  • 在多个软件包中运行脚本。你可以使用--filter标志,在workspace的多个软件包中轻松运行package.json脚本。

常见的单个包单个仓库(monorepo)的标准工作结构: image.png根目录的package.json"workspaces"键用于指示哪些子目录应该被视为monorepo单体仓库中的package或workspaces。传统上,将所有workspaces都放在一个名为packages目录中。 image.png 每个workspaces都有自己的package.json,在monorepo中引用其他包时,需要使用workspace:*作为package.json中的版本字段。 image.png

Scripts生命周期

Bun 默认不执行任意的Scripts生命周期。

npm上的软件包可以在其package.json中定义生命周期脚本。一些最常见的在下面,但还有很多其他的

  • preinstall:在安装软件包之前运行
  • postinstall:在安装软件包后运行
  • preuninstall:在卸载软件包之前运行
  • prepublishOnly:在软件包发布之前运行

这些脚本是软件包管理器在适当时间读取和执行的任意shell命令。但执行任意脚本代表着潜在的安全风险,因此,与其他npm客户端不同,Bun默认不执行任意生命周期脚本。

trustedDependencies

Bun使用“默认安全”方法,而不是执行任意脚本。您可以将某些软件包添加到允许列表中,Bun将为这些软件包执行生命周期脚本。要告诉Bun允许特定软件包的生命周期脚本,请将软件包名称添加到package.json 的trustedDependencies数组中。

--ignore-scripts

要禁用所有软件包的生命周期脚本,请使用--ignore-scripts标志。

bun install --ignore-scripts

LockFile锁文件

运行bun install将创建一个名为bun.lockb的二进制锁文件(bun.lockb); image.png

为什么bun的锁文件是二进制?

与 npm, yarn 等包管理工具不同,bun的锁文件是二进制的,为啥是二进制的,主要是基于性能考虑,Bun的锁文件保存和加载速度非常快,并且比通常在锁文件内保存的数据要多得多。

bun install 的 范围(Scopes) 和 注册表下载源(registry)

bun 默认的依赖下载范围,注册源下载源配置

  1. Bun默认的下载源注册表是:registry.npmjs.org。这个也可以在bunfig.toml中配置: image.png 要配置特定组织范围的私有注册表: image.png
  2. .npmrc: Bun目前不读取.npmrc文件。对于私有的注册表,需要在bunfig.toml中配置;

Bundler(构建打包)

Bun的快速原生构建现在处于实验阶段。它可以通过这两种方式:1. bun build的cli命令方式;2. Bun.build()的JavaScriptAPI方式来使用的。目的是配置Bun构建的行为方式;类似于 webpack 和 vite的项目配置文件(webpack.config.js, vite.config.ts)的配置方式,只不过bun还可以使用JavaScriptAPI的方式进行配置;

Bun的构建打包更快,以下是Bun构建和其他构建的的性能速度对比: image.png

注意:Bun的构建打包(bunlder)不打算取代tsc进行类型检查或者生成类型声明的。即Bun的构建的时候不会进行ts的类型检查的。

JavaScript API方式

使用JavaScript的API方式进行配置Bun的构建行为;一般是在Bun项目的入口文件(例:index.ts)中进行配置;当然了你可以在 entrypoints 指定要构建的文件;

image.png

bun build 命令方式

使用终端命令bun build,命令格式如:bun build ./index.tsx --outdir ./out

image.png

--wach: 监听观察模式,指定要构建打包的文件有变化,就会实时变化输出的文件内容;命令格式如:bun build ./index.tsx --outdir ./out --watchimage.png

构建打包中常用的API说明

  1. entrypoints: 必需参数,应用程序的入口,打包的起点;
    JavaScriptAPI方式的使用:

    const result = await Bun.build({
      entrypoints: ["./index.ts"],
    });
    // => { success: boolean, outputs: BuildArtifact[], logs: BuildMessage[] }
    

    image.png bun build命令方式的使用:bun build --entrypoints ./index.ts

  2. outdir: 构建打包后的输出文件的目录; JavaScriptAPI方式的使用:

    const result = await Bun.build({
      entrypoints: ['./index.ts'],
      outdir: './out'
    });
    // => { success: boolean, outputs: BuildArtifact[], logs: BuildMessage[] }
    

    bun build命令方式的使用:bun build --entrypoints ./index.ts --outdir ./out
    设置了outdir时,BuildArtifact中的path属性,将是 绝对路径。 image.png

  3. target: 构建打包后的预期执行环境;构建打包后的文件将运行在哪个环境;Bun对不同环境会有不同的解析规则和优化; JavaScriptAPI方式的使用:

    await Bun.build({
      entrypoints: ['./index.ts'],
      outdir: './out',
      target: 'browser', // default
    })
    

    bun build命令方式的使用:bun build --entrypoints ./index.ts --outdir ./out --target browser

    执行环境描述
    browser默认。 用于生成旨在由浏览器执行的包。在解决导入问题时,优先考虑"browser"导出条件。导入任何内置模块,likenodenode:eventsnode:path将有效,但调用一些函数(如fs.readFile)将不起作用。
    bun用于生成打算由Bun运行时运行的包。在许多情况下,没有必要捆绑服务器端代码;您可以直接执行源代码,无需修改。然而,捆绑服务器代码可以减少启动时间并提高运行性能。 如果任何入口点包含一个Bun shebang(#!/usr/bin/env bun)捆绑程序将默认为target: "bun"而不是"browser"
    node用于生成打算由Node.js运行的包。在解决导入时优先考虑"node"导出条件,并输出.mjs。将来,这将自动填充Bun全局和其他内置bun:*模块,尽管这尚未实现。

其他构建打包行为相关的配置可查看 构建打包相关的API配置

bunx工具

bunx 是 bun x 命令的 别名,bunx的cli脚手架工具,将从你的 bun 自动安装运行。对于本地安装,bunx 比 npx 更快!还记得吗?node 有个 npx ;对于本地安装的包bunxnpx约快100倍;

  1. 使用bunx从npm自动安装并运行软件包。它相当于npxyarn dlx;

    bunx cowsay "Hello world!"
    

    image.png

  2. 软件包可以在其package.json"bin"字段中声明可执行文件。这些被称为软件包可执行文件软件包二进制文件

    {
    // ... other fields
    "name": "my-cli",
        "bin": {
          "my-cli": "dist/index.js"
        }
      }
    

    这些可执行文件通常是标有shebang行的普通JavaScript文件,以指示应该使用哪个程序来执行它们。以下文件表明它应该与node一起执行。
    image.png 这些可执行文件可以用bunx运行, image.pngnpxbunx将首先检查本地安装的软件包,然后回退到从npm自动安装软件包。已安装的软件包将存储在Bun的全局缓存中,以备将来使用。

  3. 传递参数和标识;

    要将其他命令行标志和参数传递给可执行文件,请将它们放在可执行文件名称之后。 image.png

  4. Shebangs
    默认情况下,Bun尊重shebangs。如果可执行文件被标记为#!/usr/bin/env node,Bun将启动一个node进程来执行文件。然而,在某些情况下,使用Bun的运行时运行可执行文件可能是可取的,即使可执行文件指示相反。要做到这一点,请包括--bun标志。 image.png --bun标志必须出现在可执行名称之前。名称出现的标志被传递到可执行文件。 image.png 要强制面包始终与脚本一起使用,请使用shebang。 image.png

Bun的内置API使用

Bun和Node.js类似,基本的API大部分兼容,Bun自己内部也实现了一些常用的API,例:创建 HTTP服务器,WebSockets, 文件I/O等;具体如何使用请查看文档;

Bun的内置API使用请查看

参考

Bun 安装升级参考