Skip to main content
Bun 的通用插件 API 同时扩展了运行时和打包器。 插件会拦截导入并执行自定义加载逻辑,例如读取文件或转译代码。它们可以添加对其他文件类型的支持,例如 .scss.yaml。在打包器中,插件可以实现框架级功能,例如 CSS 提取、宏以及客户端与服务器代码共置。

生命周期钩子

插件注册在打包生命周期的不同阶段运行的回调:
  • onStart():打包器开始构建时运行一次
  • onResolve():模块解析之前运行
  • onLoad():模块加载之前运行
  • onBeforeParse():在文件被解析之前,在解析线程中运行零拷贝的本地插件
  • onEnd(): 打包完成后运行。

参考

类型的概览(完整的类型定义请参阅 Bun 的 bun.d.ts):
bun.d.ts

用法

插件是一个具有 name 属性和 setup 函数的 JavaScript 对象。
myPlugin.ts
在调用 Bun.build 时,将其传入 plugins 数组。
index.ts

插件生命周期

命名空间

onLoadonResolve 接受一个可选的 namespace 字符串。 每个模块都有一个命名空间。命名空间会为转译代码中的导入添加前缀;例如,一个具有 filter: /\.yaml$/namespace: "yaml:" 的加载器,会将从 ./myfile.yaml 的导入转换为 yaml:./myfile.yaml 默认命名空间是 "file",无需指定:import myModule from "./my-module.ts" 等同于 import myModule from "file:./my-module.ts" 其他常见命名空间:
  • "bun":用于 Bun 特有的模块("bun:test""bun:sqlite"
  • "node":用于 Node.js 模块("node:fs""node:path"

onStart

注册一个回调,在打包器开始新一轮构建时执行。
index.ts
回调可以返回 Promise。打包流程初始化后,打包器会等待所有 onStart() 回调完成才继续。 例如:
index.ts
在此示例中,Bun 会等待两个 onStart() 回调完成:10 秒的休眠以及向 bundle-time.txt 写入内容。
onStart() 回调(与其他所有生命周期回调一样)不能修改 build.config 对象。要修改 build.config,请直接在 setup() 函数中进行。

onResolve

为了打包项目,Bun 会遍历项目中所有模块的依赖树。对于每个导入的模块,Bun 都必须找到并读取该模块。“查找”部分称为模块“解析”。 onResolve() 插件生命周期回调配置模块的解析方式。 onResolve() 的第一个参数是一个包含 filternamespace 属性的对象。filter 是一个用于匹配导入字符串的正则表达式。两者结合起来,用于选择应用自定义解析逻辑的模块。 onResolve() 的第二个参数是一个回调,当 Bun 找到与第一个参数中定义的过滤器和命名空间匹配的模块导入时,该回调会针对每个模块导入执行一次。 回调会接收匹配模块的路径,并可以为该模块返回一个新路径。Bun 会读取新路径的内容,并将其解析为模块。 例如,将所有导入 images/ 的模块重定向到 ./public/images/
index.ts

onLoad

Bun 的打包器解析模块后,会读取并解析模块的内容。 onLoad() 插件生命周期回调会在 Bun 读取并解析模块之前修改模块的内容。 onResolve() 类似,onLoad() 的第一个参数用于选择此次 onLoad() 调用所应用的模块。 onLoad() 的第二个参数是一个回调,在 Bun 将匹配的模块内容加载到内存之前,该回调会针对每个匹配的模块执行一次。 回调会接收匹配模块的路径、其命名空间、默认加载器以及一个 defer 函数。 回调可以返回该模块新的 contents 字符串和新的 loader 例如:
index.ts
此插件会将所有形式为 import env from "env" 的导入转换为一个导出当前环境变量的 JavaScript 模块。

.defer()

传递给 onLoad 回调的参数之一是一个 defer 函数。它会返回一个 Promise,该 Promise 会在所有其他模块加载完成后解析。当模块的内容依赖于其他模块时,请等待该 Promise。
index.ts
.defer() 函数在每个 onLoad 回调中只能调用一次。

原生插件

Bun 的打包器使用原生代码编写,并使用多个线程并行加载和解析模块。JavaScript 插件运行在单个线程上,因为 JavaScript 本身是单线程的。 原生插件是暴露生命周期钩子(C ABI 函数)的 NAPI 模块。它们可以在多个线程上运行,因此比 JavaScript 插件运行得快得多,并且可以跳过将字符串传递给 JavaScript 所需的 UTF-8 -> UTF-16 转换等工作。 原生插件可以使用以下生命周期钩子:
  • onBeforeParse():在任何线程上,文件被 Bun 打包器解析前调用。
要创建原生插件,请导出一个与要实现的原生生命周期钩子签名匹配的 C ABI 函数。

用 Rust 创建原生插件

terminal
然后安装该 crate:
terminal
lib.rs 中,使用 bun_native_plugin::bun 过程宏定义实现原生插件的函数。 下面是一个实现 onBeforeParse 钩子的示例:
lib.rs
Bun.build() 中使用它:
index.ts

onBeforeParse

onBeforeParse() 回调会在 Bun 的打包器解析文件前立即运行。 它接收文件内容,并可以选择返回新的源代码。
Bun 可以从任何线程调用此回调,因此 NAPI 模块的实现必须是线程安全的。

onEnd

注册一个回调,在打包完成后运行。回调接收包含构建结果的 BuildOutput 对象,包括输出文件和任何构建信息。
index.ts
该回调可以返回一个 Promise。在所有 onEnd() 回调执行完毕之前,Bun.build() 返回的 promise 不会解析。
index.ts