Skip to content

Bun предоставляет доступ к своему внутреннему транспайлеру через класс Bun.Transpiler. Для создания экземпляра транспайлера Bun:

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

.transformSync()

Транспилируйте код синхронно с помощью метода .transformSync(). Модули не разрешаются, и код не выполняется. Результатом является строка ванильного JavaScript-кода.

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);
ts
import { __require as require } from "bun:wrap";
import * as JSX from "react/jsx-dev-runtime";
var jsx = require(JSX).jsxDEV;

export default jsx(
  "div",
  {
    children: "hi!",
  },
  undefined,
  false,
  undefined,
  this,
);

Чтобы переопределить загрузчик по умолчанию, указанный в конструкторе new Bun.Transpiler(), передайте второй аргумент в .transformSync().

ts
transpiler.transformSync("<div>hi!</div>", "tsx");

Детали">

При вызове .transformSync транспайлер запускается в том же потоке, что и выполняемый в данный момент код.

Если используется макрос, он будет запущен в том же потоке, что и транспайлер, но в отдельном цикле событий от остальной части вашего приложения. В настоящее время глобальные переменные между макросами и обычным кодом являются общими, что означает, что возможно (но не рекомендуется) обмениваться состояниями между макросами и обычным кодом. Попытка использовать узлы AST вне макроса является неопределенным поведением.


.transform()

Метод transform() — это асинхронная версия .transformSync(), которая возвращает Promise<string>.

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

Если вы не транспилируете много больших файлов, вам, вероятно, следует использовать Bun.Transpiler.transformSync. Стоимость пула потоков часто занимает больше времени, чем фактическая транспиляция кода.

ts
await transpiler.transform("<div>hi!</div>", "tsx");

Детали">

Метод .transform() запускает транспайлер в пуле рабочих потоков Bun, поэтому, если вы запустите его 100 раз, он будет работать на Math.floor($cpu_count * 0.8) потоках, не блокируя основной JavaScript-поток.

Если ваш код использует макрос, он потенциально создаст новую копию среды выполнения JavaScript Bun в этом новом потоке.

.scan()

Экземпляр Transpiler также может сканировать исходный код и возвращать список его импортов и экспортов, а также дополнительные метаданные о каждом из них. Импорты и экспорты только типов игнорируются.

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);
json
{
  "exports": ["name"],
  "imports": [
    {
      "kind": "import-statement",
      "path": "react"
    },
    {
      "kind": "import-statement",
      "path": "remix"
    },
    {
      "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() (особенно для больших файлов), но незначительно менее точен из-за некоторых оптимизаций производительности.

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);
json
[
  {
    "kind": "import-statement",
    "path": "react"
  },
  {
    "kind": "require-call",
    "path": "./cjs.js"
  },
  {
    "kind": "dynamic-import",
    "path": "./loader"
  }
]

Справочник

ts
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 как строified JSON или объект
  // Используйте это для установки пользовательской JSX-фабрики, фрагмента или источника импорта
  // Например, если вы хотите использовать Preact вместо React. Или если вы хотите использовать Emotion.
  tsconfig?: string | TSConfig,

  // Заменить импорты макросами
  macro?: MacroMap,

  // Указать набор экспортов для устранения
  // Или переименовать определенные экспорты
  exports?: {
      eliminate?: string[];
      replace?: Record<string, string>;
  },

  // Следует ли удалять неиспользуемые импорты из транспилированного файла
  // По умолчанию: false
  trimUnusedImports?: boolean,

  // Следует ли включить набор JSX-оптимизаций
  // jsxOptimizationInline ...,

  // Экспериментальная минификация пробелов
  minifyWhitespace?: boolean,

  // Следует ли встраивать постоянные значения
  // Обычно улучшает производительность и уменьшает размер пакета
  // По умолчанию: true
  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" });

Bun от www.bunjs.com.cn