執行環境套件管理器打包器測試執行器程式碼檢查格式化指南參考部落格意見回饋

轉譯器

使用 Bun 的轉譯器來轉譯 JavaScript 和 TypeScript 程式碼

Bun 將其內部轉譯器作為 Bun.Transpiler 類公開。建立例項:

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

.transformSync()

使用 .transformSync() 方法同步轉譯程式碼。轉譯器不會解析模組或執行程式碼。結果是一個原生 JavaScript 程式碼字串。

transpile.ts
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);

output
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() 傳入第二個引數。

TypeScript
transpiler.transformSync("<div>hi!</div>", "tsx");
細節說明

.transformSync 會在與呼叫程式碼相同的執行緒中執行轉譯器。

宏 會與轉譯器在同一執行緒中執行,但使用的事件迴圈與應用程式的其餘部分不同。宏和常規程式碼共享全域性變數,因此可以(但不建議)在它們之間共享狀態。在宏之外使用 AST 節點屬於未定義行為。


.transform()

transform() 方法是 .transformSync() 的非同步版本,傳回一個 Promise<string>。

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

除非你要轉譯_許多_大型檔案,否則請使用 Bun.Transpiler.transformSync。執行緒池開銷通常比轉譯本身的開銷還要高。

TypeScript
await transpiler.transform("<div>hi!</div>", "tsx");
細節說明

.transform() 方法會在 Bun 的工作執行緒池中執行轉譯器,因此執行 100 次會將工作分散到 Math.floor($cpu_count * 0.8) 個執行緒中,而不會阻塞主 JavaScript 執行緒。

如果你的程式碼使用了宏,轉譯器可能會在該新執行緒中啟動 Bun JavaScript 執行環境的新副本。

.scan()

.scan() 方法掃描原始碼,並傳回其匯入和匯出的列表,以及每一項對應的後設資料。僅型別的匯入和匯出會被忽略。

example.ts
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);
output
{
  "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() 更快(尤其是對於大型檔案),但由於效能最佳化,其準確性略低。

example.ts
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);
results
[
  {
    "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" });