# Esbuild 插件

import Esbuild from '@zh/shared/esbuild.md';

<Esbuild />

:::tip 推荐使用 SWC
相较于 esbuild，我们更推荐使用 SWC 来编译和压缩代码，因为 SWC 支持更多的语法特性、提供更好的代码压缩能力，并且产物具备更好的兼容性。

因此，我们建议你使用 SWC 而不是 esbuild，用法请参考 [SWC 插件](/plugins/plugin-swc)。

:::

## 快速开始

### 在 Modern.js 框架中使用

Modern.js 框架默认集成了 Builder 的 esbuild 插件，因此，你不需要手动安装和注册插件，只需要使用 [tools.esbuild](https://modernjs.dev/configure/app/tools/esbuild.html) 配置项即可：

```js
export default defineConfig({
  tools: {
    esbuild: {
      loader: {
        target: 'chrome61',
      },
      minimize: {
        target: 'chrome61',
      },
    },
  },
});
```

### 通过 Node API 使用

如果你直接使用了 Builder 的 Node API，那么需要手动安装和注册 esbuild 插件。

#### 安装插件

你可以通过如下的命令安装插件:

```bash
# npm
npm install @modern-js/builder-plugin-esbuild -D

# yarn
yarn add @modern-js/builder-plugin-esbuild -D

# pnpm
pnpm add @modern-js/builder-plugin-esbuild -D
```

#### 注册插件

通过 `addPlugins` 方法来注册 esbuild 插件：

```js
import { builderPluginEsbuild } from '@modern-js/builder-plugin-esbuild';

// 往 builder 实例上添加插件
builder.addPlugins([builderPluginEsbuild()]);
```

## 配置

插件默认会开启代码转译和代码压缩的功能，你也可以通过配置来自定义插件的行为。

### loader

- **类型：**

```ts
type LoaderOptions = EsbuildLoaderOptions | false | undefined;
```

- **默认值：**

```ts
const defaultOptions = {
  target: 'es2015',
  charset: builderConfig.output.charset,
};
```

这个选项用于启用 JavaScript 和 TypeScript 的转译，启用时将会使用 esbuild-loader 替换 babel-loader 和 ts-loader。

如果你需要修改转译参数，可以查看 [esbuild-loader 文档](https://github.com/privatenumber/esbuild-loader#loader)。

#### 设置 JSX 格式

在使用 esbuild 进行代码转译时，esbuild 默认会读取 `tsconfig.json` 中的 `compilerOptions.jsx` 字段，来决定使用哪种 JSX 语法。

因此，你需要在 `tsconfig.json` 中设置正确的 JSX 语法。

比如 React 项目，需要将 `compilerOptions.jsx` 设置为 `react-jsx`：

```json
{
  "compilerOptions": {
    "jsx": "react-jsx"
  }
}
```

#### 修改目标环境

通过 `target` 选项来修改代码转译的目标环境。`target` 可以直接设置为 JavaScript 语言版本，比如 `es6`，`es2020`；也可以设置为若干个目标环境，每个目标环境都是一个环境名称后跟一个版本号，比如 `['chrome58', 'edge16' ,'firefox57']`。`target` 字段的详细介绍可以参考 [esbuild - target](https://esbuild.github.io/api/#target)。

target 支持设置为以下环境：

- chrome
- edge
- firefox
- ie
- ios
- node
- opera
- safari

```ts
builderPluginEsbuild({
  loader: {
    target: 'chrome61',
  },
});
```

#### 关闭代码转译

将 `loader` 设置为 `false` 来关闭 esbuild 代码转译，此时 Builder 会继续使用 Babel 来进行代码转译。

```ts
builderPluginEsbuild({
  loader: false,
});
```

### minimize

- **类型：**

```ts
type MinimizeOptions = EsbuildMinifyOptions | false | undefined;
```

- **默认值：**

```ts
const defaultOptions = {
  css: true,
  target: 'es2015',
  format: builderTarget === 'web' ? 'iife' : undefined,
};
```

这个选项用于启用 JavaScript 和 CSS 的代码压缩。

如果你需要修改压缩参数，可以查看 [esbuild-loader 文档](https://github.com/privatenumber/esbuild-loader#minifyplugin)。

#### 修改目标环境

通过 `target` 选项来修改代码压缩的目标环境。

```ts
builderPluginEsbuild({
  minimize: {
    target: 'chrome61',
  },
});
```

#### 关闭代码压缩

将 `minimize` 设置为 `false` 来关闭 esbuild 代码压缩，此时 Builder 会继续使用 Terser 进行代码压缩。

```ts
builderPluginEsbuild({
  minimize: false,
});
```

## esbuild 局限性

虽然 esbuild 能给现有的 webpack 项目带来明显的构建性能提升，但这个工具在接入 Builder 时还存在一定的局限性，需要大家在接入的时候格外注意。

### 兼容性

使用 esbuild 进行代码转译时（即 `loader` 能力），esbuild 通常最低支持到 ES2015（即 ES6）语法，并且不具备自动注入 Polyfill 的能力。如果生产环境需要降级到 ES5 及以下的语法，建议使用 SWC 编译。

你可以通过如下的配置指定目标语法版本:

```ts
builderPluginEsbuild({
  loader: {
    target: 'es2015',
  },
});
```

使用 esbuild 进行代码压缩时（即 `minimize` 能力），esbuild 可以在生产环境中进行压缩和混淆，通常最低支持到 ES2015 语法。

如果设置压缩的 `target` 为 `es5`，需要保证所有代码已经被转义为 ES5 代码，否则会导致 esbuild 编译报错：`Transforming 'xxx' to the configured target environment ("es5") is not supported yet`。

因此，对于生产环境需要兼容 ES5 及以下语法的项目，请谨慎开启 minimize 能力，建议使用 SWC 压缩。

你可以通过如下的配置指定目标语法版本:

```ts
builderPluginEsbuild({
  minimize: {
    target: 'es2015',
  },
});
```

### 不支持 Babel 插件

使用 esbuild 进行代码转译时，诸如 `babel-plugin-import` 等原有 Babel 插件的语法编译功能在开启 esbuild 后无法使用。并且由于 Builder 底层使用的是 esbuild 的 `Transform API`，因此不支持使用额外 esbuild 插件来进行自定义编译过程。

如果你有 `babel-plugin-import` 等 Babel 插件相关诉求，可以使用 SWC 插件。

### 产物体积

使用 esbuild 压缩虽然带来了构建效率上的提升，但 esbuild 的压缩比例是低于 terser 的，因此**构建产物的体积会增大**，请根据业务情况酌情使用。通常来说，esbuild 比较适合中后台等对体积不敏感的场景。

对于压缩工具之间的详细对比，可以参考 [minification-benchmarks](https://github.com/privatenumber/minification-benchmarks)。
