新闻
Bun发布新功能Bun Macros
通过macros,可以仅将一段代码运行后的结果打包进最终代码中,而非将整段代码都打包进最终代码
举个例子,下面这段代码
// random.ts
export function random() {
return Math.random();
}
// cli.tsx
import { random } from './random.ts' with { type: 'macro' };
console.log(`Your random number is ${random()}`);
通过bun build打包后得到的脚本如下
console.log(`Your random number is ${0.6805550949689833}`);
可以看到,random函数并未出现在打包后的脚本中,Bun在打包过程中直接执行了cli.tsx中的random(),并用其执行结果替换了random(),生成了最终的脚本
Dead code elimination
Bun在执行macros并用执行结果替换了目标代码后,会删除dead code,比如下面这段代码
// returnFalse.ts
export function returnFalse() {
return false;
}
import {returnFalse} from './returnFalse.ts' with { type: 'macro' };
if (returnFalse()) {
console.log("This code is eliminated");
}
由于执行returnFalse()后得到的结果是false,条件块内的语句永远不会执行到,故打包后得到的将是一个空文件,里面没有任何代码
Security considerations
-
macro只要不被调用(即使被import了),就对打包后的代码没有任何影响和副作用,因为它根本不会被打包进代码中。 -
可以通过
--no-macros来在打包的过程中禁用macro,此时如果代码中如果使用macro,将会报错如下 -
为了减少恶意package对用户的潜在攻击,
macro在node_modules禁用。如果一个package试图调用macro,将会报错如下:不过用户可以将package作为
macro引入并调用import {macro} from "some-package" with { type: "macro" }; macro();
Limitations
macro的执行结果必须是可序列化的
序列化即把对象转化为可传输的字节序列过程
下面这段代码,由于macro的执行结果是函数(不可序列化),因此是不合法的
export function getText(url: string) {
// this doesn't work!
return () => {};
}
总结下,macro的执行结果可以是以下类型:
-
JSON-compatible的数据类型,比如下面这段代码
export function getObject() { return { foo: "bar", baz: 123, array: [ 1, 2, { nested: "value" }], }; } -
macro可以是异步函数,其执行结果也可以是Promise实例
export async function getText() { return "async value"; } -
Bun的转码器实现了对一些常见的数据格式(比如
Response、Blog、TypedArray)进行序列化的功能,比如下面这段代码,由于fetch的执行结果是Promise<Response>,该函数作为macro是合法的export function getObject() { return fetch("https://bun.sh") }
macro的参数必须是静态的
比如下面这段函数作为macro就是不合法的
import {getText} from './getText.ts' with { type: 'macro' };
export function howLong() {
// the value of `foo` cannot be statically known
const foo = Math.random() ? "foo" : "bar";
const text = getText(`https://example.com/${foo}`);
console.log("The page is ", text.length, " characters long");
}
工具
Aimless.js
一个用于生成各种随机值的库