转译器
使用 Bun 的转译器来转译 JavaScript 和 TypeScript 代码
Bun 将其内部转译器作为 Bun.Transpiler 类公开。创建实例:
const transpiler = new Bun.Transpiler({
loader: "tsx", // "js" | "jsx" | "ts" | "tsx"
});
.transformSync()
使用 .transformSync() 方法同步转译代码。转译器不会解析模块或执行代码。结果是一个原生 JavaScript 代码字符串。
const transpiler = new Bun.Transpiler({
loader: 'tsx',
});
const code = `
import * as whatever from "./whatever.ts"
export function Home(props: {title: string}){
return <p>{props.title}</p>;
}`;
const result = transpiler.transformSync(code);
import * as whatever from "./whatever.ts";
export function Home(props) {
return jsxDEV_7x81h0kn("p", {
children: props.title
}, undefined, false, undefined, this);
}
要覆盖 new Bun.Transpiler() 构造函数中指定的默认加载器,可以给 .transformSync() 传入第二个参数。
transpiler.transformSync("<div>hi!</div>", "tsx");
细节说明
.transformSync 会在与调用代码相同的线程中运行转译器。
宏 会与转译器在同一线程中运行,但使用的事件循环与应用程序的其余部分不同。宏和常规代码共享全局变量,因此可以(但不建议)在它们之间共享状态。在宏之外使用 AST 节点属于未定义行为。
.transform()
transform() 方法是 .transformSync() 的异步版本,返回一个 Promise<string>。
const transpiler = new Bun.Transpiler({ loader: "jsx" });
const result = await transpiler.transform("<div>hi!</div>");
console.log(result);
除非你要转译_许多_大型文件,否则请使用 Bun.Transpiler.transformSync。线程池开销通常比转译本身的开销还要高。
await transpiler.transform("<div>hi!</div>", "tsx");
细节说明
.transform() 方法会在 Bun 的工作线程池中运行转译器,因此运行 100 次会将工作分散到 Math.floor($cpu_count * 0.8) 个线程中,而不会阻塞主 JavaScript 线程。
如果你的代码使用了宏,转译器可能会在该新线程中启动 Bun JavaScript 运行时环境的新副本。
.scan()
.scan() 方法扫描源代码,并返回其导入和导出的列表,以及每一项对应的元数据。仅类型的导入和导出会被忽略。
const transpiler = new Bun.Transpiler({
loader: "tsx",
});
const code = `
import React from 'react';
import type {ReactNode} from 'react';
const val = require('./cjs.js')
import('./loader');
export const name = "hello";
`;
const result = transpiler.scan(code);
{
"exports": ["name"],
"imports": [
{
"kind": "import-statement",
"path": "react"
},
{
"kind": "dynamic-import",
"path": "./loader"
}
]
}
imports 数组中的每个导入项都包含 path 和 kind。Bun 将导入分类为以下几种类型:
import-statement:import React from 'react'require-call:const val = require('./cjs.js')require-resolve:require.resolve('./cjs.js')dynamic-import:import('./loader')import-rule:@import 'foo.css'url-token:url('./foo.png')
.scanImports()
在对性能敏感的代码中,使用 .scanImports() 方法获取导入列表。它比 .scan() 更快(尤其是对于大型文件),但由于性能优化,其准确性略低。
const transpiler = new Bun.Transpiler({
loader: "tsx",
});
const code = `
import React from 'react';
import type {ReactNode} from 'react';
const val = require('./cjs.js')
import('./loader');
export const name = "hello";
`;
const result = transpiler.scanImports(code);
[
{
"kind": "import-statement",
"path": "react"
},
{
"kind": "require-call",
"path": "./cjs.js"
},
{
"kind": "dynamic-import",
"path": "./loader"
}
]
参考
type Loader = "jsx" | "js" | "ts" | "tsx";
interface TranspilerOptions {
// 替换键为值,值必须是 JSON 字符串。
// { "process.env.NODE_ENV": "\"production\"" }
define?: Record<string, string>,
// 此转译器的默认加载器
loader?: Loader,
// 默认目标平台
// 影响 import 和/或 require 的使用方式
target?: "browser" | "bun" | "node",
// 指定 tsconfig.json 文件,字符串化的 JSON 或对象
// 用于设置自定义的 JSX 工厂、片段或导入源
// 例如,使用 Preact 替代 React,或使用 Emotion
tsconfig?: string | TSConfig,
// 用宏替换导入
macro?: MacroMap,
// 指定一组需剔除的导出项
// 或重命名某些导出
exports?: {
eliminate?: string[];
replace?: Record<string, string>;
},
// 是否从转译文件中移除未使用的导入
// 默认: false
trimUnusedImports?: boolean,
// 是否启用一系列 JSX 优化
// jsxOptimizationInline ...,
// 实验性空白符压缩
minifyWhitespace?: boolean,
// 是否内联常量值
// 通常可以提高性能并减小包体积
// 默认: false
inline?: boolean,
}
// 映射导入路径到宏
interface MacroMap {
// {
// "react-relay": {
// "graphql": "bun-macro-relay/bun-macro-relay.tsx"
// }
// }
[packagePath: string]: {
[importItemName: string]: string,
},
}
class Bun.Transpiler {
constructor(options: TranspilerOptions)
transform(code: string, loader?: Loader): Promise<string>
transformSync(code: string, loader?: Loader): string
scan(code: string): {exports: string[], imports: Import[]}
scanImports(code: string): Import[]
}
type Import = {
path: string,
kind:
// JavaScript 中的 import foo from 'bar';
| "import-statement"
// JavaScript 中的 require("foo")
| "require-call"
// JavaScript 中的 require.resolve("foo")
| "require-resolve"
// JavaScript 中的动态 import()
| "dynamic-import"
// CSS 中的 @import()
| "import-rule"
// CSS 中的 url()
| "url-token"
// 导入是由 Bun 注入的
| "internal"
// 入口点(不常见)
| "entry-point-build"
| "entry-point-run"
}
const transpiler = new Bun.Transpiler({ loader: "jsx" });