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