Skip to content

Bun expose son transpileur interne via la classe Bun.Transpiler. Pour créer une instance du transpileur de Bun :

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

.transformSync()

Transpilez du code de manière synchrone avec la méthode .transformSync(). Les modules ne sont pas résolus et le code n'est pas exécuté. Le résultat est une chaîne de code JavaScript vanilla.

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,
);

Pour remplacer le loader par défaut spécifié dans le constructeur new Bun.Transpiler(), passez un deuxième argument à .transformSync().

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

Détails techniques

Lorsque .transformSync est appelé, le transpileur s'exécute dans le même thread que le code actuellement exécuté.

Si une macro est utilisée, elle sera exécutée dans le même thread que le transpileur, mais dans une boucle d'événements séparée du reste de votre application. Actuellement, les globales entre les macros et le code régulier sont partagées, ce qui signifie qu'il est possible (mais non recommandé) de partager des états entre les macros et le code régulier. Tenter d'utiliser des nœuds AST en dehors d'une macro est un comportement indéfini.


.transform()

La méthode transform() est une version asynchrone de .transformSync() qui renvoie une Promise<string>.

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

À moins que vous ne transpiliez beaucoup de gros fichiers, vous devriez probablement utiliser Bun.Transpiler.transformSync. Le coût du pool de threads prendra souvent plus de temps que la transpilation du code elle-même.

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

Détails techniques

La méthode .transform() exécute le transpileur dans le pool de threads de travail de Bun, donc si vous l'exécutez 100 fois, elle l'exécutera sur Math.floor($cpu_count * 0.8) threads, sans bloquer le thread JavaScript principal.

Si votre code utilise une macro, cela pourrait potentiellement engendrer une nouvelle copie de l'environnement d'exécution JavaScript de Bun dans ce nouveau thread.


.scan()

L'instance Transpiler peut également analyser du code source et renvoyer une liste de ses imports et exports, plus des métadonnées supplémentaires sur chacun d'eux. Les imports et exports de type uniquement sont ignorés.

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"
    }
  ]
}

Chaque import dans le tableau imports a un path et un kind. Bun catégorise les imports dans les types suivants :

  • 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()

Pour le code sensible aux performances, vous pouvez utiliser la méthode .scanImports() pour obtenir une liste d'imports. C'est plus rapide que .scan() (surtout pour les gros fichiers) mais marginalement moins précis en raison de certaines optimisations de performances.

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"
  }
]

Référence

ts
type Loader = "jsx" | "js" | "ts" | "tsx";

interface TranspilerOptions {
  // Remplacer la clé par la valeur. La valeur doit être une chaîne JSON.
  // { "process.env.NODE_ENV": "\"production\"" }
  define?: Record<string, string>,

  // Loader par défaut pour ce transpileur
  loader?: Loader,

  // Plateforme par défaut à cibler
  // Cela affecte comment import et/ou require est utilisé
  target?: "browser" | "bun" | "node",

  // Spécifier un fichier tsconfig.json comme JSON sérialisé ou un objet
  // Utilisez ceci pour définir une factory JSX personnalisée, un fragment ou une source d'import
  // Par exemple, si vous voulez utiliser Preact au lieu de React. Ou si vous voulez utiliser Emotion.
  tsconfig?: string | TSConfig,

  // Remplacer les imports par des macros
  macro?: MacroMap,

  // Spécifier un ensemble d'exports à éliminer
  // Ou renommer certains exports
  exports?: {
      eliminate?: string[];
      replace?: Record<string, string>;
  },

  // S'il faut supprimer les imports inutilisés du fichier transpilé
  // Par défaut : false
  trimUnusedImports?: boolean,

  // S'il faut activer un ensemble d'optimisations JSX
  // jsxOptimizationInline ...,

  // Minification expérimentale des espaces
  minifyWhitespace?: boolean,

  // S'il faut inline les valeurs constantes
  // Améliore généralement les performances et diminue la taille du bundle
  // Par défaut : true
  inline?: boolean,
}

// Mapper les chemins d'import vers des macros
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'; en JavaScript
  | "import-statement"
  // require("foo") en JavaScript
  | "require-call"
  // require.resolve("foo") en JavaScript
  | "require-resolve"
  // Dynamic import() en JavaScript
  | "dynamic-import"
  // @import() en CSS
  | "import-rule"
  // url() en CSS
  | "url-token"
  // L'import a été injecté par Bun
  | "internal"
  // Point d'entrée (pas courant)
  | "entry-point-build"
  | "entry-point-run"
}

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

Bun édité par www.bunjs.com.cn