esbuild 配置 #

配置方式概述 #

esbuild 提供三种配置方式:

text
┌─────────────────────────────────────────────────────────────┐
│                    esbuild 配置方式                          │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  1. 命令行参数                                               │
│     └── esbuild src/index.js --bundle --minify              │
│                                                              │
│  2. JavaScript API                                           │
│     └── esbuild.build({ ... })                              │
│                                                              │
│  3. 配置文件                                                 │
│     └── esbuild.config.js / build.js                        │
│                                                              │
└─────────────────────────────────────────────────────────────┘

入口配置 #

entryPoints - 入口文件 #

指定打包的入口文件:

javascript
const esbuild = require('esbuild');

// 单入口 - 字符串
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  outdir: 'dist',
});

// 单入口 - 数组
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  outdir: 'dist',
});

// 多入口 - 数组
esbuild.build({
  entryPoints: ['src/index.js', 'src/admin.js'],
  bundle: true,
  outdir: 'dist',
});

// 多入口 - 对象(自定义输出名称)
esbuild.build({
  entryPoints: {
    main: 'src/index.js',
    admin: 'src/admin.js',
    vendor: 'src/vendor.js',
  },
  bundle: true,
  outdir: 'dist',
});

stdin - 内联代码 #

直接传入代码字符串:

javascript
const esbuild = require('esbuild');

const result = esbuild.buildSync({
  stdin: {
    contents: `
      import { greet } from './greet.js';
      console.log(greet('World'));
    `,
    resolveDir: __dirname,
    sourcefile: 'virtual-entry.js',
    loader: 'js',
  },
  bundle: true,
  outfile: 'dist/bundle.js',
});

absWorkingDir - 工作目录 #

指定工作目录:

javascript
esbuild.build({
  absWorkingDir: '/path/to/project',
  entryPoints: ['src/index.js'],
  bundle: true,
  outdir: 'dist',
});

输出配置 #

outfile 与 outdir #

javascript
// 单文件输出
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  outfile: 'dist/bundle.js',
});

// 多文件输出目录
esbuild.build({
  entryPoints: ['src/index.js', 'src/admin.js'],
  bundle: true,
  outdir: 'dist',
});

format - 输出格式 #

javascript
// IIFE - 立即执行函数(浏览器直接使用)
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  format: 'iife',
  outfile: 'dist/bundle.js',
});
// 输出: (function() { ... })();

// ESM - ES 模块
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  format: 'esm',
  outfile: 'dist/bundle.mjs',
});
// 输出: import { ... } from '...'; export default ...;

// CJS - CommonJS
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  format: 'cjs',
  outfile: 'dist/bundle.cjs',
});
// 输出: const ... = require('...'); module.exports = ...;

// UMD - 通用模块定义
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  format: 'umd',
  globalName: 'MyLibrary',
  outfile: 'dist/bundle.umd.js',
});
// 输出: (function (global, factory) { ... })(this, function() { ... });

globalName - 全局变量名 #

用于 UMD 和 IIFE 格式:

javascript
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  format: 'iife',
  globalName: 'MyApp',
  outfile: 'dist/bundle.js',
});

// 输出后可通过 window.MyApp 访问

支持嵌套命名:

javascript
esbuild.build({
  globalName: 'com.example.myApp',
  // 输出: window.com = { example: { myApp: ... } }
});

platform - 目标平台 #

javascript
// 浏览器平台
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  platform: 'browser',
  outfile: 'dist/bundle.js',
});

// Node.js 平台
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  platform: 'node',
  outfile: 'dist/bundle.js',
});

// 中性平台
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  platform: 'neutral',
  outfile: 'dist/bundle.js',
});

平台差异:

特性 browser node neutral
默认格式 iife cjs esm
Node.js 内置模块 不打包 打包 不打包
process.env 替换 保留 保留
__dirname/__filename 不定义 定义 不定义

target - 目标环境 #

javascript
// 指定 ES 版本
esbuild.build({
  target: 'es2020',
});

// 指定浏览器版本
esbuild.build({
  target: ['chrome80', 'firefox78', 'safari14', 'edge80'],
});

// 指定 Node.js 版本
esbuild.build({
  platform: 'node',
  target: ['node16', 'node18', 'node20'],
});

// 混合指定
esbuild.build({
  target: ['es2020', 'chrome80', 'node16'],
});

sourcemap - Source Map #

javascript
// 不生成 Source Map(默认)
esbuild.build({
  sourcemap: false,
});

// 生成外部 Source Map 文件
esbuild.build({
  sourcemap: true,  // 或 'external'
  outfile: 'dist/bundle.js',
});
// 生成 bundle.js 和 bundle.js.map

// 内联 Source Map
esbuild.build({
  sourcemap: 'inline',
  outfile: 'dist/bundle.js',
});

// 内联并返回 Source Map
esbuild.build({
  sourcemap: 'linked',
  sourcesContent: false,  // 不包含源代码
});

在输出文件中添加内容:

javascript
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  outfile: 'dist/bundle.js',
  banner: {
    js: '// Copyright 2024 My Company\n// Licensed under MIT',
    css: '/* Copyright 2024 My Company */',
  },
  footer: {
    js: 'console.log("Build time: " + new Date().toISOString());',
    css: '/* End of styles */',
  },
});

entryNames 与 chunkNames #

自定义输出文件名:

javascript
esbuild.build({
  entryPoints: {
    main: 'src/index.js',
    admin: 'src/admin.js',
  },
  bundle: true,
  outdir: 'dist',
  entryNames: '[name]-[hash]',
  chunkNames: 'chunks/[name]-[hash]',
});

// 输出:
// dist/main-A1B2C3D4.js
// dist/admin-E5F6G7H8.js
// dist/chunks/vendor-I9J0K1L2.js

占位符说明:

占位符 说明
[name] 入口名称
[hash] 内容哈希
[dir] 相对目录

assetNames #

静态资源命名:

javascript
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  outdir: 'dist',
  loader: {
    '.png': 'file',
    '.svg': 'file',
  },
  assetNames: 'assets/[name]-[hash]',
});

// 图片输出到 dist/assets/ 目录

模块处理配置 #

external - 外部模块 #

排除不打包的模块:

javascript
// 数组形式
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  outfile: 'dist/bundle.js',
  external: ['lodash', 'react', 'react-dom'],
});

// 函数形式(高级用法)
esbuild.build({
  external: (id) => {
    // 排除所有 node_modules
    if (id.includes('node_modules')) {
      return true;
    }
    // 排除特定前缀
    if (id.startsWith('@myorg/')) {
      return true;
    }
    return false;
  },
});

packages - 包处理方式 #

javascript
// 排除所有依赖
esbuild.build({
  packages: 'external',
  bundle: true,
});

// 默认行为(打包所有依赖)
esbuild.build({
  packages: 'bundle',
  bundle: true,
});

alias - 路径别名 #

javascript
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  outfile: 'dist/bundle.js',
  alias: {
    '@': './src',
    '@components': './src/components',
    '@utils': './src/utils',
    '@hooks': './src/hooks',
    '@types': './src/types',
  },
});

使用示例:

javascript
// 原来
import { Button } from '../../../components/Button';
import { formatDate } from '../../../utils/date';

// 使用别名后
import { Button } from '@/components/Button';
import { formatDate } from '@utils/date';

mainFields - 主字段 #

指定 package.json 中使用的字段:

javascript
// 默认值(browser 平台)
esbuild.build({
  mainFields: ['browser', 'module', 'main'],
});

// Node.js 平台默认
esbuild.build({
  platform: 'node',
  mainFields: ['main', 'module'],
});

// 自定义
esbuild.build({
  mainFields: ['es2015', 'module', 'main'],
});

conditions - 条件导出 #

javascript
esbuild.build({
  conditions: ['production', 'browser'],
});

// 对应 package.json 中的条件导出
// {
//   "exports": {
//     ".": {
//       "production": "./dist/prod.js",
//       "development": "./dist/dev.js",
//       "default": "./dist/index.js"
//     }
//   }
// }

resolveExtensions - 解析扩展名 #

javascript
esbuild.build({
  resolveExtensions: ['.tsx', '.ts', '.jsx', '.js', '.json', '.css'],
});

优化配置 #

minify - 压缩 #

javascript
// 完整压缩
esbuild.build({
  minify: true,
});

// 分别控制
esbuild.build({
  minifyWhitespace: true,    // 移除空白
  minifyIdentifiers: true,   // 缩短变量名
  minifySyntax: true,        // 优化语法
});

// 只压缩空白(保留可读性)
esbuild.build({
  minifyWhitespace: true,
  minifyIdentifiers: false,
  minifySyntax: false,
});

drop - 移除代码 #

javascript
// 移除 console
esbuild.build({
  drop: ['console'],
});

// 移除 debugger
esbuild.build({
  drop: ['debugger'],
});

// 同时移除
esbuild.build({
  drop: ['console', 'debugger'],
});

pure - 纯函数标记 #

javascript
esbuild.build({
  pure: ['console.log', 'console.info', 'console.debug'],
});

// 被标记的函数如果结果未使用,将被移除
// console.log('debug info') 会被移除

ignoreAnnotations - 忽略注释 #

javascript
esbuild.build({
  ignoreAnnotations: true,
});
// 忽略 /* @__PURE__ */ 和 /* @__NO_SIDE_EFFECTS__ */ 注释

legalComments - 法律注释 #

javascript
// 内联注释(默认)
esbuild.build({
  legalComments: 'inline',
});

// 提取到外部文件
esbuild.build({
  legalComments: 'external',
  outfile: 'dist/bundle.js',
});
// 生成 bundle.js.LEGAL.txt

// 返回注释内容
esbuild.build({
  legalComments: 'linked',
});

// 保留原始位置
esbuild.build({
  legalComments: 'eof',
});

// 移除所有注释
esbuild.build({
  legalComments: 'none',
});

treeShaking - Tree Shaking #

javascript
// 默认启用
esbuild.build({
  treeShaking: true,
});

// 禁用(保留所有代码)
esbuild.build({
  treeShaking: false,
});

// 忽略副作用注释
esbuild.build({
  treeShaking: 'ignore-annotations',
});

定义和替换 #

define - 全局定义 #

javascript
esbuild.build({
  define: {
    'process.env.NODE_ENV': '"production"',
    'process.env.VERSION': '"1.0.0"',
    'process.env.DEBUG': 'false',
    'global': 'globalThis',
  },
});

使用表达式:

javascript
esbuild.build({
  define: {
    'process.env.API_URL': JSON.stringify('https://api.example.com'),
    'process.env.BUILD_TIME': JSON.stringify(new Date().toISOString()),
  },
});

inject - 注入文件 #

javascript
// inject.js
export const process = { env: { NODE_ENV: 'production' } };

// 配置
esbuild.build({
  inject: ['./inject.js'],
  define: {
    // 如果需要替换全局 process
    'process': 'process',
  },
});

常见用途 - 注入 Node.js polyfill:

javascript
// node-polyfills.js
export const process = {
  env: {},
  version: 'v18.0.0',
};

export const Buffer = class Buffer {
  static from(str) { return str; }
};

export const __dirname = '/';
export const __filename = '/index.js';

Loader 配置 #

loader - 文件加载器 #

javascript
esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  outdir: 'dist',
  loader: {
    '.js': 'js',
    '.jsx': 'jsx',
    '.ts': 'ts',
    '.tsx': 'tsx',
    '.css': 'css',
    '.module.css': 'local-css',
    '.json': 'json',
    '.txt': 'text',
    '.png': 'dataurl',
    '.jpg': 'file',
    '.svg': 'file',
    '.woff': 'file',
    '.woff2': 'file',
  },
});

各加载器详解 #

JavaScript 加载器 #

javascript
loader: {
  '.js': 'js',      // 标准 JavaScript
  '.jsx': 'jsx',    // JavaScript + JSX
  '.ts': 'ts',      // TypeScript
  '.tsx': 'tsx',    // TypeScript + JSX
  '.mjs': 'js',     // ES 模块
  '.cjs': 'js',     // CommonJS
}

CSS 加载器 #

javascript
loader: {
  '.css': 'css',           // 标准 CSS
  '.local.css': 'local-css', // CSS Modules
}

数据加载器 #

javascript
loader: {
  '.json': 'json',    // JSON 对象
  '.txt': 'text',     // 文本字符串
  '.binary': 'binary', // 二进制数据
}

文件加载器 #

javascript
loader: {
  '.png': 'dataurl',  // Base64 内联
  '.jpg': 'file',     // 复制文件
  '.svg': 'file',     // 复制文件
  '.woff': 'file',    // 复制文件
  '.pdf': 'copy',     // 复制到输出目录
}

JSX 配置 #

jsx - JSX 转换模式 #

javascript
// 经典模式(默认)
esbuild.build({
  jsx: 'transform',
  jsxFactory: 'React.createElement',
  jsxFragment: 'React.Fragment',
});

// 自动模式(React 17+)
esbuild.build({
  jsx: 'automatic',
  jsxImportSource: 'react',
});

// 保留模式
esbuild.build({
  jsx: 'preserve',
});

jsxFactory 与 jsxFragment #

javascript
// Preact
esbuild.build({
  jsxFactory: 'h',
  jsxFragment: 'Fragment',
});

// 自定义
esbuild.build({
  jsxFactory: 'createElement',
  jsxFragment: 'Fragment',
});

jsxImportSource #

javascript
// React
esbuild.build({
  jsx: 'automatic',
  jsxImportSource: 'react',
});

// Emotion
esbuild.build({
  jsx: 'automatic',
  jsxImportSource: '@emotion/react',
});

// 自定义路径
esbuild.build({
  jsx: 'automatic',
  jsxImportSource: '@/jsx-runtime',
});

构建元数据 #

metafile - 元数据输出 #

javascript
const result = await esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  outdir: 'dist',
  metafile: true,
});

console.log(result.metafile);

// 分析元数据
const analysis = await esbuild.analyzeMetafile(result.metafile);
console.log(analysis);

输出到文件:

bash
esbuild src/index.js --bundle --metafile=meta.json --outfile=dist/bundle.js

分析构建结果 #

javascript
const esbuild = require('esbuild');
const fs = require('fs');

async function analyze() {
  const result = await esbuild.build({
    entryPoints: ['src/index.js'],
    bundle: true,
    metafile: true,
    outfile: 'dist/bundle.js',
  });

  const analysis = await esbuild.analyzeMetafile(result.metafile, {
    verbose: true,
  });

  console.log(analysis);
}

analyze();

输出示例:

text
  dist/bundle.js  125.2kb
├ src/index.js     45.2kb
├ node_modules/lodash/index.js  35.1kb
├ src/utils.js     25.0kb
└ src/components.js  19.9kb

增量构建 #

context API #

javascript
const esbuild = require('esbuild');

async function setup() {
  const ctx = await esbuild.context({
    entryPoints: ['src/index.js'],
    bundle: true,
    outfile: 'dist/bundle.js',
  });

  // 手动重新构建
  await ctx.rebuild();

  // 启用监听
  await ctx.watch();

  // 启动服务
  const { host, port } = await ctx.serve({
    servedir: 'dist',
  });

  console.log(`Server: http://${host}:${port}`);
}

setup();

rebuild - 手动重建 #

javascript
const ctx = await esbuild.context({
  entryPoints: ['src/index.js'],
  bundle: true,
  outfile: 'dist/bundle.js',
});

// 首次构建
await ctx.rebuild();

// 文件变化后再次构建
await ctx.rebuild();

// 清理
await ctx.dispose();

watch - 监听模式 #

javascript
const ctx = await esbuild.context({
  entryPoints: ['src/index.js'],
  bundle: true,
  outfile: 'dist/bundle.js',
});

await ctx.watch();

// 停止监听
// await ctx.dispose();

serve - 开发服务器 #

javascript
const ctx = await esbuild.context({
  entryPoints: ['src/index.js'],
  bundle: true,
  outdir: 'dist',
});

const server = await ctx.serve({
  port: 3000,
  host: 'localhost',
  servedir: 'dist',
  onRequest: (args) => {
    console.log(`${args.method} ${args.path} - ${args.status}`);
  },
});

console.log(`Server running at http://${server.host}:${server.port}`);

完整配置示例 #

库开发配置 #

javascript
const esbuild = require('esbuild');

const sharedConfig = {
  entryPoints: ['src/index.ts'],
  bundle: true,
  sourcemap: true,
  external: ['react', 'react-dom'],
  loader: {
    '.ts': 'ts',
    '.tsx': 'tsx',
  },
};

async function build() {
  // ESM
  await esbuild.build({
    ...sharedConfig,
    format: 'esm',
    outfile: 'dist/index.esm.js',
  });

  // CommonJS
  await esbuild.build({
    ...sharedConfig,
    format: 'cjs',
    outfile: 'dist/index.cjs.js',
  });

  // UMD
  await esbuild.build({
    ...sharedConfig,
    format: 'umd',
    globalName: 'MyLib',
    outfile: 'dist/index.umd.js',
  });

  console.log('Build complete!');
}

build();

应用开发配置 #

javascript
const esbuild = require('esbuild');

const isDev = process.env.NODE_ENV !== 'production';

async function build() {
  const ctx = await esbuild.context({
    entryPoints: ['src/index.tsx'],
    bundle: true,
    outdir: 'dist',
    format: 'esm',
    platform: 'browser',
    target: ['es2020', 'chrome80', 'firefox78', 'safari14'],
    sourcemap: isDev,
    minify: !isDev,
    define: {
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
    },
    loader: {
      '.tsx': 'tsx',
      '.ts': 'ts',
      '.css': 'css',
      '.png': 'dataurl',
      '.svg': 'file',
    },
    alias: {
      '@': './src',
    },
  });

  if (isDev) {
    await ctx.watch();
    const { host, port } = await ctx.serve({
      servedir: 'dist',
      port: 3000,
    });
    console.log(`Dev server: http://${host}:${port}`);
  } else {
    await ctx.rebuild();
    await ctx.dispose();
    console.log('Build complete!');
  }
}

build().catch(() => process.exit(1));

Node.js 应用配置 #

javascript
const esbuild = require('esbuild');

esbuild.build({
  entryPoints: ['src/server.ts'],
  bundle: true,
  platform: 'node',
  target: 'node18',
  format: 'cjs',
  outfile: 'dist/server.js',
  external: [
    'express',
    'mongoose',
    'redis',
    // 其他生产依赖
  ],
  loader: {
    '.ts': 'ts',
  },
  minify: true,
  sourcemap: true,
}).then(() => {
  console.log('Server build complete!');
});

下一步 #

现在你已经掌握了 esbuild 的详细配置,接下来学习 插件系统 扩展 esbuild 的能力!

最后更新:2026-03-28