Skip to content

Bun 模块系统

Bun 支持多种模块系统,包括 ES Modules (ESM)、CommonJS (CJS) 和 Bun 专有的模块解析。本章介绍 Bun 的模块系统及其特性。

ES Modules (ESM)

ES Modules 是 JavaScript 的标准模块系统,也是 Bun 推荐使用的方式。

导出模块

typescript
// math.ts

// 命名导出
export const PI = 3.14159;

export function add(a: number, b: number): number {
  return a + b;
}

export function multiply(a: number, b: number): number {
  return a * b;
}

// 默认导出
export default class Calculator {
  add(a: number, b: number) {
    return a + b;
  }
  
  subtract(a: number, b: number) {
    return a - b;
  }
}

导入模块

typescript
// main.ts

// 导入默认导出
import Calculator from "./math";

// 导入命名导出
import { PI, add, multiply } from "./math";

// 导入全部并命名
import * as math from "./math";

// 混合导入
import Calculator, { PI, add } from "./math";

// 使用
const calc = new Calculator();
console.log(calc.add(2, 3));
console.log(add(2, 3));
console.log(math.PI);

动态导入

typescript
// 动态导入(返回 Promise)
async function loadModule() {
  const math = await import("./math");
  console.log(math.add(2, 3));
  
  // 条件导入
  if (process.env.NODE_ENV === "development") {
    const devTools = await import("./dev-tools");
    devTools.init();
  }
}

重新导出

typescript
// index.ts - 模块聚合

// 重新导出全部
export * from "./math";
export * from "./string";

// 重新导出部分
export { add, multiply } from "./math";

// 重命名导出
export { add as sum } from "./math";

// 重新导出默认导出
export { default as Calculator } from "./math";

CommonJS (CJS)

Bun 完全支持 CommonJS 模块系统,确保与现有 Node.js 生态兼容。

CommonJS 导出

javascript
// utils.js

// 导出单个值
module.exports = function greet(name) {
  return `Hello, ${name}!`;
};

// 导出多个值
module.exports = {
  greet: function(name) {
    return `Hello, ${name}!`;
  },
  farewell: function(name) {
    return `Goodbye, ${name}!`;
  }
};

// 使用 exports 快捷方式
exports.greet = function(name) {
  return `Hello, ${name}!`;
};

exports.farewell = function(name) {
  return `Goodbye, ${name}!`;
};

CommonJS 导入

javascript
// main.js

// 导入整个模块
const utils = require("./utils");
console.log(utils.greet("Bun"));

// 解构导入
const { greet, farewell } = require("./utils");
console.log(greet("Bun"));

ESM 与 CJS 互操作

在 ESM 中导入 CJS

typescript
// cjs-module.js (CommonJS)
module.exports = {
  name: "CJS Module",
  greet() {
    return "Hello from CJS!";
  }
};

// esm-main.ts (ESM)
import cjsModule from "./cjs-module.js";
console.log(cjsModule.greet());

// 命名导入也可以工作(Bun 会自动处理)
import { name, greet } from "./cjs-module.js";

在 CJS 中导入 ESM

javascript
// esm-module.ts (ESM)
export const message = "Hello from ESM!";
export default { name: "ESM Module" };

// cjs-main.js (CommonJS)
// 使用动态 import()
const loadESM = async () => {
  const esmModule = await import("./esm-module.ts");
  console.log(esmModule.message);
  console.log(esmModule.default);
};

loadESM();

模块解析

解析顺序

Bun 按以下顺序解析模块:

  1. 内置模块bun:*node:*
  2. 绝对路径/path/to/module
  3. 相对路径./module../module
  4. node_modules:向上查找 node_modules

文件扩展名

typescript
// Bun 会按顺序尝试以下扩展名
import { foo } from "./module";

// 尝试顺序:
// 1. ./module.ts
// 2. ./module.tsx
// 3. ./module.js
// 4. ./module.jsx
// 5. ./module/index.ts
// 6. ./module/index.tsx
// 7. ./module/index.js
// 8. ./module/index.jsx

路径别名

tsconfig.json 中配置:

json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components/*": ["src/components/*"],
      "@utils/*": ["src/utils/*"]
    }
  }
}

使用别名:

typescript
import { Button } from "@components/Button";
import { formatDate } from "@utils/date";
import config from "@/config";

Bun 内置模块

bun 模块

typescript
// 直接使用 Bun 全局对象
console.log(Bun.version);

// 或导入 bun 模块
import { $ } from "bun";

await $`echo "Hello from Bun Shell"`;

常用 bun:* 模块

typescript
// SQLite
import { Database } from "bun:sqlite";

// FFI(外部函数接口)
import { dlopen, FFIType } from "bun:ffi";

// 测试
import { test, expect } from "bun:test";

// 密码哈希
import { password } from "bun";

Node.js 内置模块

Bun 支持大部分 Node.js 内置模块:

typescript
// 文件系统
import fs from "fs";
import { readFile } from "fs/promises";

// 路径处理
import path from "path";

// HTTP
import http from "http";
import https from "https";

// 其他常用模块
import os from "os";
import crypto from "crypto";
import util from "util";
import events from "events";
import stream from "stream";
import buffer from "buffer";

使用 node: 前缀

typescript
// 推荐使用 node: 前缀(更明确)
import fs from "node:fs";
import path from "node:path";
import { Buffer } from "node:buffer";

JSON 和其他文件导入

导入 JSON

typescript
// 直接导入 JSON
import config from "./config.json";
console.log(config.apiUrl);

// 类型安全的 JSON 导入
import packageJson from "./package.json" with { type: "json" };
console.log(packageJson.version);

导入文本文件

typescript
// 导入为字符串
import readme from "./README.md" with { type: "text" };
console.log(readme);

导入 TOML

typescript
// 导入 TOML 配置
import config from "./config.toml";
console.log(config.database.host);

模块缓存

缓存机制

Bun 会缓存已加载的模块,同一模块只会执行一次:

typescript
// counter.ts
let count = 0;

export function increment() {
  return ++count;
}

// main.ts
import { increment } from "./counter";
import { increment as inc } from "./counter";

console.log(increment()); // 1
console.log(inc());       // 2 (同一个模块实例)

清除缓存

typescript
// 在测试中可能需要清除缓存
delete require.cache[require.resolve("./module")];

循环依赖

处理循环依赖

typescript
// a.ts
import { b } from "./b";
export const a = "A";
console.log("a.ts loaded, b =", b);

// b.ts
import { a } from "./a";
export const b = "B";
console.log("b.ts loaded, a =", a);

// main.ts
import { a } from "./a";
// 输出:
// b.ts loaded, a = undefined
// a.ts loaded, b = B

避免循环依赖

typescript
// 方法1: 延迟导入
export function getA() {
  const { a } = require("./a");
  return a;
}

// 方法2: 重构代码,提取共享模块
// shared.ts - 共享的代码
// a.ts - 导入 shared
// b.ts - 导入 shared

package.json 配置

type 字段

json
{
  "type": "module"  // 使用 ESM
}
json
{
  "type": "commonjs"  // 使用 CJS(默认)
}

exports 字段

json
{
  "name": "my-package",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs",
      "types": "./dist/index.d.ts"
    },
    "./utils": {
      "import": "./dist/utils.mjs",
      "require": "./dist/utils.cjs"
    }
  }
}

条件导出

json
{
  "exports": {
    ".": {
      "bun": "./src/index.ts",
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs",
      "default": "./dist/index.js"
    }
  }
}

Bun 会优先使用 bun 条件。

小结

本章介绍了:

  • ✅ ES Modules 的导入导出语法
  • ✅ CommonJS 模块系统
  • ✅ ESM 与 CJS 互操作
  • ✅ 模块解析规则和路径别名
  • ✅ Bun 和 Node.js 内置模块
  • ✅ JSON、TOML 等文件导入
  • ✅ 模块缓存和循环依赖处理

下一步

继续阅读 TypeScript 支持 了解 Bun 对 TypeScript 的原生支持。

本站内容仅供学习和研究使用。