Bun 模块系统 #

概述 #

Bun 支持多种模块格式,包括 ES 模块(ESM)、CommonJS(CJS),并提供了灵活的模块解析机制。Bun 默认使用 ESM,同时兼容 CommonJS。

ES 模块(ESM) #

基本语法 #

typescript
// 导出
// utils.ts
export const PI = 3.14159;

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

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

// 默认导出
export default function greet(name: string) {
  return `Hello, ${name}!`;
}
typescript
// 导入
// main.ts
import greet, { PI, add, Calculator } from "./utils";

console.log(greet("Bun"));
console.log(PI);
console.log(add(1, 2));
const calc = new Calculator();

命名导出 #

typescript
// 命名导出
export const name = "Bun";
export const version = "1.2.0";

// 导出列表
const a = 1;
const b = 2;
export { a, b };

// 重命名导出
export { a as alpha, b as beta };

// 导出时重命名
export { add as sum };

// 聚合导出
export { add, subtract } from "./math";
export * from "./utils";
export * as utils from "./utils";

默认导出 #

typescript
// 默认导出函数
export default function () {
  return "Hello";
}

// 默认导出类
export default class User {
  constructor(public name: string) {}
}

// 默认导出表达式
export default {
  name: "Bun",
  version: "1.2.0",
};

// 默认导出值
export default "Hello World";

导入方式 #

typescript
// 命名导入
import { add, subtract } from "./math";

// 重命名导入
import { add as sum } from "./math";

// 默认导入
import greet from "./greet";

// 混合导入
import greet, { name, version } from "./module";

// 命名空间导入
import * as math from "./math";
console.log(math.add(1, 2));

// 仅执行(副作用)
import "./setup";

// 动态导入
const module = await import("./module");

类型导入 #

typescript
// 类型导入
import type { User, Product } from "./types";

// 混合导入
import { User, type Product } from "./types";

// 类型导出
export type { User, Product };
export type * from "./types";

CommonJS(CJS) #

基本语法 #

javascript
// 导出
// utils.cjs
const PI = 3.14159;

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

module.exports = {
  PI,
  add,
};

// 或逐个导出
exports.PI = 3.14159;
exports.add = add;
javascript
// 导入
// main.cjs
const { PI, add } = require("./utils");

console.log(PI);
console.log(add(1, 2));

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

module.exports vs exports #

javascript
// exports 是 module.exports 的引用
exports.a = 1;          // 正确:添加属性
exports.b = 2;          // 正确:添加属性

// 错误:重新赋值会断开引用
exports = { a: 1, b: 2 }; // 错误!

// 正确:重新赋值 module.exports
module.exports = { a: 1, b: 2 }; // 正确!

CJS 与 ESM 互操作 #

typescript
// ESM 导入 CJS
// main.ts (ESM)
import { add } from "./utils.cjs";  // 直接导入
const utils = require("./utils.cjs"); // 使用 require
javascript
// CJS 导入 ESM
// main.cjs
const module = require("./module.mjs");
// 注意:ESM 默认导出在 .default 属性
const greet = module.default;

模块解析 #

解析规则 #

Bun 按以下顺序解析模块:

text
1. 相对路径
   import "./utils"
   import "./utils.ts"
   import "./utils/index.ts"

2. 绝对路径
   import "/src/utils"

3. node_modules
   import "react"
   import "lodash/get"

4. Bun 内置模块
   import { Database } from "bun:sqlite"

扩展名解析 #

typescript
// Bun 自动尝试以下扩展名
import "./utils";      // 查找顺序:
                       // ./utils.ts
                       // ./utils.tsx
                       // ./utils.js
                       // ./utils.jsx
                       // ./utils.json
                       // ./utils/index.ts
                       // ./utils/index.tsx
                       // ...

目录解析 #

typescript
// 目录导入
import "./utils";      // 解析为 ./utils/index.ts

// package.json 的 exports/main
import "my-package";   // 使用 package.json 的 exports 或 main

package.json exports #

json
{
  "name": "my-package",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs",
      "types": "./dist/index.d.ts"
    },
    "./utils": {
      "import": "./dist/utils.mjs",
      "types": "./dist/utils.d.ts"
    },
    "./styles/*": "./dist/styles/*"
  },
  "main": "./dist/index.cjs",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts"
}
typescript
// 使用
import something from "my-package";
import { util } from "my-package/utils";
import "my-package/styles/main.css";

条件导出 #

json
{
  "exports": {
    ".": {
      "bun": "./dist/bun.js",
      "worker": "./dist/worker.js",
      "browser": "./dist/browser.js",
      "node": "./dist/node.js",
      "default": "./dist/index.js"
    }
  }
}

导入映射(Import Maps) #

基本用法 #

创建 import_map.json

json
{
  "imports": {
    "react": "https://esm.sh/react@18",
    "react-dom": "https://esm.sh/react-dom@18",
    "lodash": "https://esm.sh/lodash@4",
    "@/": "./src/"
  }
}

bunfig.toml 中配置:

toml
[run]
preload = ["./import_map.json"]

或使用命令行:

bash
bun --import-map=import_map.json run index.ts

使用示例 #

typescript
// 使用导入映射
import react from "react";
import { debounce } from "lodash";
import { helper } from "@/utils/helper";

// 等价于
import react from "https://esm.sh/react@18";
import { debounce } from "https://esm.sh/lodash@4";
import { helper } from "./src/utils/helper";

作用域映射 #

json
{
  "imports": {
    "react": "https://esm.sh/react@18"
  },
  "scopes": {
    "./legacy/": {
      "react": "https://esm.sh/react@16"
    }
  }
}
typescript
// 根目录使用 React 18
import react from "react";

// legacy 目录使用 React 16
// legacy/app.ts
import react from "react";  // React 16

包管理 #

npm 包 #

typescript
// 安装后直接导入
import React from "react";
import { useState } from "react";
import express from "express";
import { z } from "zod";

从 URL 导入 #

typescript
// 从 URL 直接导入
import confetti from "https://esm.sh/canvas-confetti";
import { marked } from "https://esm.sh/marked";

// 带版本
import React from "https://esm.sh/react@18.2.0";

Bun 内置模块 #

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

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

// FFI
import { dlopen, suffix } from "bun:ffi";

// WebSocket
import { serve } from "bun";

动态导入 #

基本用法 #

typescript
// 动态导入模块
const module = await import("./module.ts");
console.log(module.default);

// 条件导入
if (condition) {
  const heavy = await import("./heavy-module");
  heavy.doSomething();
}

// 动态路径
const name = "utils";
const utils = await import(`./${name}.ts`);

懒加载 #

typescript
// 懒加载组件
async function loadComponent() {
  const { Button } = await import("./components/Button");
  return Button;
}

// 使用
const Button = await loadComponent();

模块缓存 #

typescript
// Bun 缓存动态导入
const mod1 = await import("./module");
const mod2 = await import("./module");
console.log(mod1 === mod2);  // true - 同一实例

// 清除缓存(需要重启进程)

模块元数据 #

import.meta #

typescript
// 文件路径
console.log(import.meta.path);     // 文件绝对路径
console.log(import.meta.dir);      // 文件所在目录
console.log(import.meta.file);     // 文件名

// URL 形式
console.log(import.meta.url);      // file:///path/to/file.ts

// 主模块检查
if (import.meta.main) {
  console.log("This is the main module");
}

// 环境
console.log(import.meta.env);      // 环境变量

// 开发/生产判断
if (import.meta.dev) {
  console.log("Development mode");
}

使用示例 #

typescript
// 获取当前目录
const currentDir = import.meta.dir;

// 加载相邻文件
const config = await Bun.file(`${import.meta.dir}/config.json`).json();

// 主入口检查
if (import.meta.main) {
  startServer();
}

循环依赖 #

问题示例 #

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

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

解决方案 #

typescript
// 方案一:延迟导入
// a.ts
export const a = "a";
export function getB() {
  const { b } = require("./b");
  return b;
}

// 方案二:重构模块结构
// types.ts - 共享类型
export interface Shared { ... }

// a.ts - 只依赖 types
// b.ts - 只依赖 types

// 方案三:使用函数延迟访问
// a.ts
import { getB } from "./b";
export const a = "a";
export function getA() { return a; }

// b.ts
import { getA } from "./a";
export const b = "b";
export function getB() { return b; }
console.log(getA());

最佳实践 #

文件组织 #

text
src/
├── index.ts           # 入口文件
├── modules/
│   ├── user/
│   │   ├── index.ts   # 模块入口
│   │   ├── service.ts
│   │   └── types.ts
│   └── product/
│       ├── index.ts
│       ├── service.ts
│       └── types.ts
├── utils/
│   ├── index.ts
│   ├── helpers.ts
│   └── constants.ts
└── types/
    └── index.ts

导出风格 #

typescript
// 推荐:集中导出
// utils/index.ts
export * from "./helpers";
export * from "./constants";
export * from "./validators";

// 使用
import { helper, constant, validate } from "./utils";

// 不推荐:分散导入
import { helper } from "./utils/helpers";
import { constant } from "./utils/constants";
import { validate } from "./utils/validators";

类型导出 #

typescript
// types/index.ts
export type { User, Product } from "./models";
export type { ApiResponse } from "./api";

// 使用
import type { User, Product } from "./types";

下一步 #

现在你已经了解了 Bun 的模块系统,接下来学习 TypeScript 支持 深入了解 Bun 的 TypeScript 集成。

最后更新:2026-03-29