> ## Documentation Index
> Fetch the complete documentation index at: https://bun.ll1025.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 转译器

> 使用 Bun 的转译器转译 JavaScript 和 TypeScript 代码

Bun 将其内部转译器暴露为 `Bun.Transpiler` 类。要创建实例：

```ts theme={null}
const transpiler = new Bun.Transpiler({
  loader: "tsx", // "js" | "jsx" | "ts" | "tsx"
});
```

***

## `.transformSync()`

使用 `.transformSync()` 方法同步转译代码。模块不会被解析，代码也不会被执行。结果是纯 JavaScript 代码的字符串。

<CodeGroup>
  ```ts transpile.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23"  theme={null}
  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);

  ```

  ```ts output theme={null}
  import * as whatever from "./whatever.ts";
  export function Home(props) {
    return jsxDEV_7x81h0kn("p", {
      children: props.title
    }, undefined, false, undefined, this);
  }
  ```
</CodeGroup>

要覆盖在 `new Bun.Transpiler()` 构造函数中指定的默认 loader，请向 `.transformSync()` 传递第二个参数。

```ts theme={null}
transpiler.transformSync("<div>hi!</div>", "tsx");
```

<Accordion title="深入细节">
  `.transformSync` 在与调用代码相同的线程中运行转译器。

  [宏](/bundler/macros)与转译器在同一个线程中运行，但与应用程序的其余部分在单独的事件循环中运行。宏和常规代码共享全局变量，因此它们之间共享状态是可能（但不推荐）的。在宏之外使用 AST 节点是未定义行为。
</Accordion>

***

## `.transform()`

`transform()` 方法是 `.transformSync()` 的异步版本，返回一个 `Promise<string>`。

```js theme={null}
const transpiler = new Bun.Transpiler({ loader: "jsx" });
const result = await transpiler.transform("<div>hi!</div>");
console.log(result);
```

除非您要转译**许多**大文件，否则请使用 `Bun.Transpiler.transformSync`。线程池的开销通常比转译本身还要大。

```ts theme={null}
await transpiler.transform("<div>hi!</div>", "tsx");
```

<Accordion title="深入细节">
  `.transform()` 方法在 Bun 的 worker 线程池中运行转译器，因此运行 100 次会在 `Math.floor($cpu_count * 0.8)` 个线程之间分配工作，而不会阻塞主 JavaScript 线程。

  如果您的代码使用了宏，它可能会在该新线程中生成一个新的 Bun JavaScript 运行时环境副本。
</Accordion>

## `.scan()`

`.scan()` 方法扫描源代码并返回其导入和导出的列表，以及每个的元数据。[类型专用](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)的导入和导出会被忽略。

<CodeGroup>
  ```ts example.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
  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);
  ```

  ```json output theme={null}
  {
    "exports": ["name"],
    "imports": [
      {
        "kind": "import-statement",
        "path": "react"
      },
      {
        "kind": "dynamic-import",
        "path": "./loader"
      }
    ]
  }
  ```
</CodeGroup>

`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()` 更快（特别是对于大文件），但由于性能优化，精度略有降低。

<CodeGroup>
  ```ts example.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
  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);
  ```

  ```json results icon="file-json" theme={null}
  [
    {
      "kind": "import-statement",
      "path": "react"
    },
    {
      "kind": "require-call",
      "path": "./cjs.js"
    },
    {
      "kind": "dynamic-import",
      "path": "./loader"
    }
  ]
  ```
</CodeGroup>

***

## 参考

```ts 查看 TypeScript 定义 可展开 theme={null}
type Loader = "jsx" | "js" | "ts" | "tsx";

interface TranspilerOptions {
  // 用 value 替换 key。Value 必须是 JSON 字符串。
  // { "process.env.NODE_ENV": "\"production\"" }
  define?: Record<string, string>,

  // 此转译器的默认 loader
  loader?: Loader,

  // 默认的目标平台
  // 这会影响 import 和/或 require 的使用方式
  target?: "browser" | "bun" | "node",

  // 指定 tsconfig.json 文件，作为字符串化 JSON 或对象
  // 用于设置自定义 JSX 工厂、fragment 或导入源
  // 例如，如果您想使用 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:
  // import foo from 'bar'; 在 JavaScript 中
  | "import-statement"
  // require("foo") 在 JavaScript 中
  | "require-call"
  // require.resolve("foo") 在 JavaScript 中
  | "require-resolve"
  // Dynamic import() 在 JavaScript 中
  | "dynamic-import"
  // @import() 在 CSS 中
  | "import-rule"
  // url() 在 CSS 中
  | "url-token"
  // 导入由 Bun 注入
  | "internal"
  // 入口点（不常见）
  | "entry-point-build"
  | "entry-point-run"
}

const transpiler = new Bun.Transpiler({ loader: "jsx" });
```
