2025.09.01

极致性能:使用 ESBuild 极速构建

🎯 为什么选择 ESBuild?

核心优势 ⬇️

特性描述速度对比
🚀 闪电般的速度使用 Go 语言编写,实现了数倍于传统工具链的性能提升。Webpack 快 10–100 倍
🛠️ 极简配置开箱即用,强大的默认配置让复杂构建变得简单。接近零配置
📦 灵活的输出原生支持主流模块格式,适应各种使用环境。支持 ESM CJS IIFE
🧠 TypeScript 原生支持无需 Babel 或额外的 tsc 预编译步骤。直接解析 ts 文件
🔄 实时反馈内置文件监听 (watch),提供即时的重编译反馈。优秀的开发体验

🚀 快速上手

步骤 1️⃣:配置开发脚本

package.json 中添加开发脚本:

{
  "scripts": {
    "dev": "node scripts/dev.js reactivity --format esm"
  }
}

运行效果:

  • 🚀 启动开发模式
  • 👀 监听文件变更并实时构建
  • 📦 以 ESM 格式输出到 dist 目录

步骤 2️⃣:创建构建脚本

新建 scripts 目录,并在里面创建 dev.js 文件:

/**
 * 🔥 ESBuild Monorepo 开发构建脚本
 *
 * 功能:
 * - 📁 支持任意 packages/* 子包作为构建目标。
 * - 🎯 灵活控制输出格式(esm/cjs/iife)。
 * - 👀 启用实时 watch 模式。
 * - 🗺️ 自动生成 Source Map。
 *
 * 示例用法:
 * pnpm dev reactivity --format esm
 * pnpm dev vue -f cjs
 */

import { createRequire } from 'node:module'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { parseArgs } from 'node:util'
import esbuild from 'esbuild'

// 🔧 工具函数:解决 ESM 环境下的兼容性问题
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const require = createRequire(import.meta.url)

// 📝 1. 解析命令行参数
const {
  values: { format },
  positionals
} = parseArgs({
  allowPositionals: true,
  options: {
    format: { type: 'string', short: 'f', default: 'esm' } // 默认输出 ESM 格式
  }
})

// 🎯 2. 确定构建目标和路径
const target = positionals.length ? positionals[0] : 'vue' // 默认构建 vue 包
const entry = resolve(__dirname, `../packages/${target}/src/index.ts`)
const outfile = resolve(__dirname, `../packages/${target}/dist/${target}.${format}.js`)

// 📦 3. 读取包配置 (用于获取 globalName)
const pkg = require(`../packages/${target}/package.json`)

// 🚀 4. 启动 ESBuild 构建上下文并监听
esbuild
  .context({
    entryPoints: [entry], // 📥 入口文件
    outfile, // 📤 输出路径
    format: format === 'iife' ? 'iife' : format, // 🎨 确保 iife 格式正确
    platform: format === 'cjs' ? 'node' : 'browser', // 🌐 目标运行环境
    sourcemap: true, // 🗺️ 启用 Source Map
    bundle: true, // 📦 启用打包 (将依赖内联)
    globalName: pkg.buildOptions?.name // 🏷️ 配置 IIFE 模式下的全局变量名
  })
  .then((ctx) => {
    console.log(`\n👀 Watching for changes in @vue/${target}...`)
    return ctx.watch() // 👀 启动文件监听
  })

📋 过检参数

参数说明可选值默认值
位置参数指定要构建的包名reactivity, vue, sharedvue
--format / -f输出格式esm, cjs, iifeesm

🎨 输出格式对比

格式用途特点
ESM现代浏览器、Node.js原生模块系统,Tree-shaking 友好
CJSNode.js 环境CommonJS 格式,向后兼容
IIFE浏览器直接引入立即执行函数,全局变量

🚀 使用示例

# 1. 开发 reactivity 包,以 ESM 格式输出
pnpm dev reactivity --format esm

# 2. 构建 vue 包,用于 Node.js 服务端渲染 (CommonJS)
pnpm dev vue -f cjs

# 3. 构建 shared 包,用于浏览器直接引入 (IIFE)
pnpm dev shared --format iife

📁 输出结构

构建完成后,文件会输出到对应包的 dist 目录:

packages/
├── reactivity/
│   └── dist/
│       ├── reactivity.esm.js      # ESM 格式
│       ├── reactivity.cjs.js      # CommonJS 格式
│       └── reactivity.iife.js     # IIFE 格式
└── vue/
    └── dist/
        ├── vue.esm.js
        ├── vue.cjs.js
        └── vue.iife.js