Skip to content

Bun 打包构建

Bun 内置了高性能的打包器(Bundler),可以将 JavaScript/TypeScript 代码打包用于浏览器或服务器。本章介绍 Bun 打包器的使用方法。

基本打包

命令行打包

bash
# 基本打包
bun build ./src/index.ts --outdir ./dist

# 指定输出文件
bun build ./src/index.ts --outfile ./dist/bundle.js

# 生成 source map
bun build ./src/index.ts --outdir ./dist --sourcemap

# 压缩代码
bun build ./src/index.ts --outdir ./dist --minify

API 打包

typescript
// build.ts
const result = await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
});

if (!result.success) {
  console.error("构建失败:");
  for (const log of result.logs) {
    console.error(log);
  }
} else {
  console.log("构建成功!");
  for (const output of result.outputs) {
    console.log("输出:", output.path);
  }
}

构建选项

完整配置

typescript
const result = await Bun.build({
  // 入口文件(可以多个)
  entrypoints: ["./src/index.ts", "./src/worker.ts"],
  
  // 输出目录
  outdir: "./dist",
  
  // 目标环境
  target: "browser", // "browser" | "bun" | "node"
  
  // 模块格式
  format: "esm", // "esm" | "cjs" | "iife"
  
  // 代码分割
  splitting: true,
  
  // 压缩
  minify: true,
  // 或分别设置
  // minify: {
  //   whitespace: true,
  //   identifiers: true,
  //   syntax: true,
  // },
  
  // Source Map
  sourcemap: "external", // "none" | "inline" | "external"
  
  // 命名模式
  naming: {
    entry: "[name].[hash].js",
    chunk: "[name]-[hash].js",
    asset: "[name]-[hash][ext]",
  },
  
  // 外部依赖(不打包)
  external: ["react", "react-dom"],
  
  // 定义全局常量
  define: {
    "process.env.NODE_ENV": JSON.stringify("production"),
    __VERSION__: JSON.stringify("1.0.0"),
  },
  
  // 插件
  plugins: [],
  
  // 加载器配置
  loader: {
    ".png": "file",
    ".svg": "text",
  },
  
  // 公共路径
  publicPath: "/assets/",
  
  // 根目录
  root: "./src",
});

目标环境

浏览器目标

typescript
await Bun.build({
  entrypoints: ["./src/app.ts"],
  outdir: "./dist",
  target: "browser",
  
  // 浏览器环境特定选项
  format: "esm",
  splitting: true,
  minify: true,
});

Node.js 目标

typescript
await Bun.build({
  entrypoints: ["./src/server.ts"],
  outdir: "./dist",
  target: "node",
  
  // Node.js 特定
  format: "cjs", // 或 "esm"
  external: ["*"], // 不打包 node_modules
});

Bun 目标

typescript
await Bun.build({
  entrypoints: ["./src/app.ts"],
  outdir: "./dist",
  target: "bun",
  
  // Bun 运行时优化
});

代码分割

自动代码分割

typescript
await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  splitting: true, // 启用代码分割
});

动态导入

typescript
// src/index.ts
// 动态导入会自动分割为单独的 chunk
const module = await import("./heavy-module.ts");
module.doSomething();

// 条件导入
if (needFeature) {
  const feature = await import("./feature.ts");
  feature.init();
}

多入口分割

typescript
await Bun.build({
  entrypoints: [
    "./src/pages/home.ts",
    "./src/pages/about.ts",
    "./src/pages/contact.ts",
  ],
  outdir: "./dist",
  splitting: true,
});

// 共享代码会自动提取到公共 chunk

资源处理

内置加载器

typescript
await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  loader: {
    // 作为文件输出(返回 URL)
    ".png": "file",
    ".jpg": "file",
    ".gif": "file",
    ".woff2": "file",
    
    // 作为文本导入
    ".txt": "text",
    ".md": "text",
    ".html": "text",
    
    // 作为 JSON 导入
    ".json": "json",
    
    // 作为 Base64 数据 URL
    ".svg": "dataurl",
    
    // 作为二进制数据
    ".bin": "binary",
    
    // JavaScript/TypeScript
    ".js": "js",
    ".ts": "ts",
    ".jsx": "jsx",
    ".tsx": "tsx",
    
    // CSS
    ".css": "css",
  },
});

导入资源

typescript
// 导入图片(返回 URL)
import logoUrl from "./logo.png";
const img = document.createElement("img");
img.src = logoUrl;

// 导入文本
import readme from "./README.md" with { type: "text" };
console.log(readme);

// 导入 JSON
import config from "./config.json";
console.log(config.version);

CSS 处理

导入 CSS

typescript
// 导入 CSS 文件
import "./styles.css";

// CSS 模块(实验性)
import styles from "./component.module.css";
element.className = styles.container;

CSS 打包

typescript
await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  
  // CSS 会自动打包
});

外部依赖

排除依赖

typescript
await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  
  // 不打包这些依赖
  external: ["react", "react-dom", "lodash"],
});

排除所有 node_modules

typescript
await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  
  // 使用通配符排除所有
  external: ["*"],
});

动态排除

typescript
import { dependencies } from "./package.json";

await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  external: Object.keys(dependencies),
});

环境变量替换

define 选项

typescript
await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  define: {
    "process.env.NODE_ENV": JSON.stringify("production"),
    "process.env.API_URL": JSON.stringify("https://api.example.com"),
    __DEV__: "false",
    __VERSION__: JSON.stringify("1.0.0"),
  },
});

代码中使用

typescript
// src/index.ts
if (process.env.NODE_ENV === "development") {
  console.log("开发模式");
}

console.log("版本:", __VERSION__);
console.log("API:", process.env.API_URL);

插件系统

插件接口

typescript
import type { BunPlugin } from "bun";

const myPlugin: BunPlugin = {
  name: "my-plugin",
  
  setup(build) {
    // 拦截模块解析
    build.onResolve({ filter: /^virtual:/ }, (args) => {
      return {
        path: args.path,
        namespace: "virtual",
      };
    });
    
    // 拦截模块加载
    build.onLoad({ filter: /.*/, namespace: "virtual" }, (args) => {
      return {
        contents: `export default "${args.path}"`,
        loader: "js",
      };
    });
  },
};

await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  plugins: [myPlugin],
});

YAML 插件示例

typescript
import { parse as parseYaml } from "yaml";

const yamlPlugin: BunPlugin = {
  name: "yaml-loader",
  
  setup(build) {
    build.onLoad({ filter: /\.ya?ml$/ }, async (args) => {
      const text = await Bun.file(args.path).text();
      const data = parseYaml(text);
      
      return {
        contents: `export default ${JSON.stringify(data)}`,
        loader: "js",
      };
    });
  },
};

// 使用
import config from "./config.yaml";
console.log(config);

环境变量插件

typescript
const envPlugin: BunPlugin = {
  name: "env-plugin",
  
  setup(build) {
    build.onResolve({ filter: /^env:/ }, (args) => {
      return {
        path: args.path.slice(4), // 移除 "env:" 前缀
        namespace: "env",
      };
    });
    
    build.onLoad({ filter: /.*/, namespace: "env" }, (args) => {
      const value = Bun.env[args.path] || "";
      return {
        contents: `export default ${JSON.stringify(value)}`,
        loader: "js",
      };
    });
  },
};

// 使用
import apiKey from "env:API_KEY";

构建脚本

package.json 配置

json
{
  "scripts": {
    "build": "bun run build.ts",
    "build:dev": "bun run build.ts --mode development",
    "build:prod": "bun run build.ts --mode production"
  }
}

完整构建脚本

typescript
// build.ts
const mode = Bun.argv.includes("--mode")
  ? Bun.argv[Bun.argv.indexOf("--mode") + 1]
  : "production";

const isDev = mode === "development";

console.log(`构建模式: ${mode}`);

// 清理输出目录
await Bun.$`rm -rf dist`;

// 构建客户端代码
const clientResult = await Bun.build({
  entrypoints: ["./src/client/index.tsx"],
  outdir: "./dist/public",
  target: "browser",
  format: "esm",
  splitting: true,
  minify: !isDev,
  sourcemap: isDev ? "inline" : "external",
  define: {
    "process.env.NODE_ENV": JSON.stringify(mode),
  },
  naming: {
    entry: isDev ? "[name].js" : "[name].[hash].js",
    chunk: isDev ? "[name].js" : "[name].[hash].js",
  },
});

if (!clientResult.success) {
  console.error("客户端构建失败");
  process.exit(1);
}

// 构建服务端代码
const serverResult = await Bun.build({
  entrypoints: ["./src/server/index.ts"],
  outdir: "./dist",
  target: "bun",
  format: "esm",
  minify: !isDev,
  external: ["*"], // 不打包依赖
});

if (!serverResult.success) {
  console.error("服务端构建失败");
  process.exit(1);
}

// 复制静态文件
await Bun.$`cp -r ./public/* ./dist/public/`;

console.log("构建完成!");
console.log("客户端文件:");
clientResult.outputs.forEach(o => console.log("  ", o.path));
console.log("服务端文件:");
serverResult.outputs.forEach(o => console.log("  ", o.path));

与其他工具对比

速度对比

打包 React 应用(含依赖):
┌────────────────────────────────────────────┐
│ webpack  ██████████████████████████  12s   │
│ esbuild  ████                        1.5s  │
│ bun      ███                         1.1s  │
└────────────────────────────────────────────┘

功能对比

功能BunesbuildwebpackVite
速度极快极快
配置复杂度
插件生态成长中有限丰富丰富
代码分割
HMR
TypeScript需插件

小结

本章介绍了:

  • ✅ 命令行和 API 打包方式
  • ✅ 构建选项和目标环境
  • ✅ 代码分割和资源处理
  • ✅ 外部依赖和环境变量
  • ✅ 插件系统
  • ✅ 完整构建脚本示例

下一步

继续阅读 测试运行器 了解 Bun 的内置测试框架。

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