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 读取新路径的内容并将其解析为模块。 例如,将所有对 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,在所有其他模块加载完成后解析。当模块的内容依赖于其他模块时,等待它。
index.ts
每个 onLoad 回调只能调用一次 .defer() 函数。

原生插件

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
回调可以返回一个 PromiseBun.build() 返回的 Promise 在所有 onEnd() 回调完成后才会 resolve。
index.ts