入门指南
#安装esbuild
首先,在本地下载并安装esbuild命令。可以使用npm 安装预构建的原生可执行文件(在安装node JavaScript运行时时会自动安装npm):
npm install --save-exact --save-dev esbuild
这应该已经在本地的node_modules
文件夹中安装了esbuild。 你可以运行esbuild可执行文件来验证一切是否正常工作:
./node_modules/.bin/esbuild --version
.\node_modules\.bin\esbuild --version
安装esbuild的推荐方式是使用npm安装原生可执行文件。但如果你不想这样做, 还有一些其他安装方式。
#你的第一个打包
这是一个关于esbuild功能和使用方法的快速实例。首先,安装react
和react-dom
包:
npm install react react-dom
然后创建一个名为app.jsx
的文件,包含以下代码:
import * as React from 'react'
import * as Server from 'react-dom/server'
let Greet = () => <h1>Hello, world!</h1>
console.log(Server.renderToString(<Greet />))
最后,告诉esbuild打包该文件:
./node_modules/.bin/esbuild app.jsx --bundle --outfile=out.js
.\node_modules\.bin\esbuild app.jsx --bundle --outfile=out.js
这应该已经创建了一个名为out.js
的文件,其中包含你的代码 和React库打包在一起。这段代码是完全独立的,不再依赖于你的node_modules
目录。 如果你使用node out.js
运行代码,你应该会看到类似这样的输出:
<h1 data-reactroot="">Hello, world!</h1>
注意,esbuild还将JSX语法转换为JavaScript,除了.jsx
扩展名外,不需要任何其他配置。 虽然esbuild可以配置,但它尝试提供合理的默认值,使许多常见情况自动工作。 如果你想在.js
文件中使用JSX语法,可以使用--loader:.js=jsx
标志告诉esbuild允许这样做。 你可以在API文档中阅读更多关于可用配置选项的信息。
#构建脚本
你的构建命令是你将重复运行的东西,所以你会想要自动化它。 一个自然的方式是在你的package.json
文件中添加一个构建脚本,如下所示:
{
"scripts": {
"build": "esbuild app.jsx --bundle --outfile=out.js"
}
}
注意,这直接使用esbuild
命令,而不是相对路径。这是可行的,因为scripts
部分中的所有内容 都是在路径中已经包含esbuild
命令的情况下运行的(只要你已经安装了该包)。
构建脚本可以这样调用:
npm run build
然而,如果你需要向esbuild传递许多选项,使用命令行界面可能会变得笨重。 对于更复杂的用途,你可能想使用esbuild的JavaScript API编写构建脚本。 它可能看起来像这样(注意,这段代码必须保存在扩展名为.mjs
的文件中, 因为它使用了import
关键字):
import * as esbuild from 'esbuild'
await esbuild.build({
entryPoints: ['app.jsx'],
bundle: true,
outfile: 'out.js',
})
build
函数在子进程中运行esbuild可执行文件,并返回一个在构建完成时解析的promise。 还有一个非异步的buildSync
API,但异步API更适合构建脚本,因为插件 只能与异步API一起使用。你可以在API文档中阅读更多关于构建API配置选项的信息。
#为浏览器打包
打包工具默认输出适用于浏览器的代码,因此无需额外配置即可开始使用。 对于开发构建,你可能想使用--sourcemap
启用源码映射, 对于生产构建,你可能想使用--minify
启用代码压缩。 你可能还想为你支持的浏览器配置目标环境, 以便将太新的JavaScript语法转换为较旧的JavaScript语法。所有这些可能看起来像这样:
esbuild app.jsx --bundle --minify --sourcemap --target=chrome58,firefox57,safari11,edge16
import * as esbuild from 'esbuild'
await esbuild.build({
entryPoints: ['app.jsx'],
bundle: true,
minify: true,
sourcemap: true,
target: ['chrome58', 'firefox57', 'safari11', 'edge16'],
outfile: 'out.js',
})
package main
import "github.com/evanw/esbuild/pkg/api"
import "os"
func main() {
result := api.Build(api.BuildOptions{
EntryPoints: []string{"app.jsx"},
Bundle: true,
MinifyWhitespace: true,
MinifyIdentifiers: true,
MinifySyntax: true,
Engines: []api.Engine{
{api.EngineChrome, "58"},
{api.EngineFirefox, "57"},
{api.EngineSafari, "11"},
{api.EngineEdge, "16"},
},
Write: true,
})
if len(result.Errors) > 0 {
os.Exit(1)
}
}
你想使用的某些npm包可能不是为在浏览器中运行而设计的。 有时你可以使用esbuild的配置选项来解决某些问题并成功打包这些包。 未定义的全局变量可以在简单情况下使用define功能替换, 或在更复杂情况下使用inject功能替换。
#为node打包
即使在使用node时不需要打包,有时将代码与esbuild一起处理也是有好处的。 打包可以自动剥离TypeScript类型,将ECMAScript模块语法转换为CommonJS, 并将新的JavaScript语法转换为旧语法,以便为特定版本的node处理。 它可能有助于在发布之前打包你的包,以便它是一个更小的下载, 并且它花费更少的时间从文件系统中读取。
如果你正在打包将要在node中运行的代码,你应该配置平台设置, 通过传递--platform=
给esbuild。 这同时改变了几个设置为node友好的默认值。例如,所有内置到node中的包,如fs
, 都会自动标记为外部包,因此esbuild不会尝试打包它们。此设置还会禁用 package.json
中的浏览器字段解释。
如果你的代码使用新的JavaScript语法,但无法在您的node版本中运行, 您将希望配置node的目标版本:
esbuild app.js --bundle --platform=node --target=node10.4
import * as esbuild from 'esbuild'
await esbuild.build({
entryPoints: ['app.js'],
bundle: true,
platform: 'node',
target: ['node10.4'],
outfile: 'out.js',
})
package main
import "github.com/evanw/esbuild/pkg/api"
import "os"
func main() {
result := api.Build(api.BuildOptions{
EntryPoints: []string{"app.js"},
Bundle: true,
Platform: api.PlatformNode,
Engines: []api.Engine{
{api.EngineNode, "10.4"},
},
Write: true,
})
if len(result.Errors) > 0 {
os.Exit(1)
}
}
你也可能不想与esbuild打包你的依赖。 有许多node特定的功能是esbuild在打包时无法支持的,如__dirname
、import.meta.url
、fs.readFileSync
, 以及*.node
本机二进制模块。你可以通过设置packages 为外部来排除所有依赖:
esbuild app.jsx --bundle --platform=node --packages=external
require('esbuild').buildSync({
entryPoints: ['app.jsx'],
bundle: true,
platform: 'node',
packages: 'external',
outfile: 'out.js',
})
package main
import "github.com/evanw/esbuild/pkg/api"
import "os"
func main() {
result := api.Build(api.BuildOptions{
EntryPoints: []string{"app.jsx"},
Bundle: true,
Platform: api.PlatformNode,
Packages: api.PackagesExternal,
Write: true,
})
if len(result.Errors) > 0 {
os.Exit(1)
}
}
如果这样做,你的依赖必须仍然在文件系统中存在,因为它们不再包含在打包中。
#同时平台
你不能在一个操作系统上安装esbuild,复制node_modules
目录到另一个操作系统, 而不重新安装,然后再在该操作系统上运行esbuild。这不会起作用,因为esbuild是用本机代码编写的, 需要安装平台特定的本机可执行文件。通常这不是问题,因为您通常会检查您的package.json
文件 进入版本控制,而不是您的node_modules
目录,然后每个人都会在克隆存储库后在本地机器上运行 npm install
。
但是,人们有时会进入这种情况,方法是安装esbuild 在Windows或macOS上,并将他们的node_modules
目录复制到 Docker图像,该图像运行Linux,或者在Windows和WSL 环境之间复制他们的node_modules
目录。获取此工作的方法取决于您的包管理器:
npm/pnpm: 如果你使用npm或pnpm安装,你可以尝试不在复制文件时复制
node_modules
目录,并在复制后在目标平台上运行npm ci
或npm install
。或者你可以考虑使用Yarn, 它内置支持在多个平台上安装包。Yarn: 如果你使用Yarn,你可以尝试在
.yarnrc.yml
文件中列出此平台和 其他平台,使用supportedArchitectures功能。 请记住,这意味着文件系统上会有多个esbuild副本。
你也可以在macOS计算机上进入这种情况,如果你使用ARM版本的npm安装esbuild, 然后尝试使用x86-64版本的node运行esbuild。在这种情况下,一个简单的修复方法是 使用ARM版本的node运行你的代码,你可以在这里下载:https://nodejs.org/en/download/。
另一个选择是使用esbuild-wasm
包代替, 它以相同的方式在所有平台上工作。但它带来了巨大的性能成本,有时可能比esbuild
包慢10倍。 所以你可能也不想这样做。
#使用Yarn Plug'n'Play
Yarn的Plug'n'Play包 安装策略受esbuild的本机支持。要使用它,请确保运行esbuild, 以便当前工作目录包含Yarn生成的包清单JavaScript文件( 无论是.pnp.cjs
还是.pnp.js
)。如果检测到Yarn Plug'n'Play包清单, esbuild将自动解析包导入到Yarn包缓存中的.zip
文件中, 并在打包时自动提取这些文件。
因为esbuild是用Go编写的,支持Yarn Plug'n'Play的完整重新实现是在Go中,而不是依赖于Yarn的JavaScript API。
这允许Yarn Plug'n'Play包解析与esbuild的完全并行化打包管道很好地集成,以实现最大速度。
请注意,Yarn的命令行界面为每个命令添加了大量不可避免的性能开销。
为了实现最大esbuild性能,你可能想考虑不使用Yarn的CLI运行esbuild(即不使用yarn esbuild
)。
这可以使esbuild运行速度提高10倍。
#其他安装方式
安装esbuild的推荐方式是使用npm安装原生可执行文件。 但你也可以以这些方式安装esbuild:
#下载构建
如果你有一个Unix系统,你可以使用以下命令下载 当前平台的esbuild
二进制可执行文件(它将下载到当前工作目录):
curl -fsSL https://esbuild.github.io/dl/v0.25.5 | sh
你也可以使用latest
而不是版本号来下载 esbuild的最新版本:
curl -fsSL https://esbuild.github.io/dl/latest | sh
如果你不想评估从互联网下载的shell脚本来下载esbuild,你也可以手动下载 包从npm自己,而不是(所有这些都是上面的shell脚本正在做的)。 虽然预编译的本机可执行文件使用npm托管,但你实际上不需要npm来下载它们。 npm包注册表是一个正常的HTTP服务器,包是正常的gzip tar文件。
这里是一个直接下载二进制可执行文件的示例:
curl -O https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz tar xzf ./darwin-x64-0.25.5.tgz ./package/bin/esbuild Usage: esbuild [options] [entry points] ...
在@esbuild/darwin-x64
包中的本机可执行文件是为macOS 操作系统和64位Intel架构设计的。截至撰写本文时,这是esbuild支持的平台本机可执行文件的完整列表:
Package name | OS | Architecture | Download |
---|---|---|---|
@esbuild/aix-ppc64 |
aix |
ppc64 |
|
@esbuild/android-arm |
android |
arm |
|
@esbuild/android-arm64 |
android |
arm64 |
|
@esbuild/android-x64 |
android |
x64 |
|
@esbuild/darwin-arm64 |
darwin |
arm64 |
|
@esbuild/darwin-x64 |
darwin |
x64 |
|
@esbuild/freebsd-arm64 |
freebsd |
arm64 |
|
@esbuild/freebsd-x64 |
freebsd |
x64 |
|
@esbuild/linux-arm |
linux |
arm |
|
@esbuild/linux-arm64 |
linux |
arm64 |
|
@esbuild/linux-ia32 |
linux |
ia32 |
|
@esbuild/linux-loong64 |
linux |
loong64 2 |
|
@esbuild/linux-mips64el |
linux |
mips64el 2 |
|
@esbuild/linux-ppc64 |
linux |
ppc64 |
|
@esbuild/linux-riscv64 |
linux |
riscv64 2 |
|
@esbuild/linux-s390x |
linux |
s390x |
|
@esbuild/linux-x64 |
linux |
x64 |
|
@esbuild/netbsd-arm64 |
netbsd 1 |
arm64 |
|
@esbuild/netbsd-x64 |
netbsd 1 |
x64 |
|
@esbuild/openbsd-arm64 |
openbsd |
arm64 |
|
@esbuild/openbsd-x64 |
openbsd |
x64 |
|
@esbuild/sunos-x64 |
sunos |
x64 |
|
@esbuild/win32-arm64 |
win32 |
arm64 |
|
@esbuild/win32-ia32 |
win32 |
ia32 |
|
@esbuild/win32-x64 |
win32 |
x64 |
为什么这不推荐: 这种方法仅适用于可以运行shell脚本的Unix系统,因此需要WSL 在Windows上。另一个缺点是您无法使用插件 与本机版本的esbuild一起使用。
如果你选择编写自己的代码从npm下载esbuild,那么你依赖于esbuild的本机可执行文件安装器的内部实现细节。 这些细节可能会在某个时候发生变化,在这种情况下,此方法将不再适用于新的esbuild版本。 但这只是一个次要的缺点,因为该方法应该永远为现有的esbuild版本(发布到npm的包是不可变的)工作。
#安装WASM版本
除了esbuild
npm包之外,还有一个esbuild-wasm
包,它功能类似,但使用WebAssembly而不是本机代码。安装它还会安装一个名为esbuild
的可执行文件:
npm install --save-exact esbuild-wasm
为什么这不推荐: WebAssembly版本比本机版本慢得多。在许多情况下,它慢一个数量级(即10倍)。 这是由于各种原因,包括a)node每次运行时都会重新编译WebAssembly代码, b)Go的WebAssembly编译方法单线程, c)node有WebAssembly错误,可能会延迟进程退出几秒钟。 WebAssembly版本还排除了一些功能,如本地文件服务器。 你应该只在没有其他选择的情况下才使用WebAssembly包,例如当你想在不受支持的平台 上使用esbuild时。WebAssembly包主要旨在仅用于在浏览器中使用。
#Deno而不是node
还有对Deno JavaScript环境的初步支持,如果你想使用esbuild与它,而不是node。 包托管在https://deno.land/x/esbuild 并使用本机esbuild可执行文件。可执行文件将从npm下载并缓存到本地,因此您的计算机需要网络访问 registry.npmjs.org才能使用此包。使用此包看起来像这样:
import * as esbuild from 'https://deno.land/x/esbuild@v0.25.5/mod.js'
let ts = 'let test: boolean = true'
let result = await esbuild.transform(ts, { loader: 'ts' })
console.log('result:', result)
await esbuild.stop()
它基本上与esbuild的npm包具有相同的API,只有一个附加功能: 你需要在完成时调用stop()
,因为与node不同,Deno没有提供必要的API, 允许Deno退出,而esbuild的内部子进程仍在运行。
如果你想使用esbuild的WebAssembly实现而不是esbuild的本机实现与Deno,你可以这样做, 通过导入wasm.js
而不是mod.js
,如下所示:
import * as esbuild from 'https://deno.land/x/esbuild@v0.25.5/wasm.js'
let ts = 'let test: boolean = true'
let result = await esbuild.transform(ts, { loader: 'ts' })
console.log('result:', result)
await esbuild.stop()
使用WebAssembly而不是本机意味着你不需要指定Deno的 --allow-run
权限,并且WebAssembly是唯一的选择, 在文件系统不可用的情况下,如Deno Deploy。 但是,请记住,WebAssembly版本的esbuild比本机版本慢得多。 另一个关于WebAssembly的事情是,Deno目前有一个错误, 其中进程终止被不必要的延迟,直到所有加载的WebAssembly模块完全优化, 这可能需要很多秒。如果你正在编写一个短暂的脚本, 使用esbuild的WebAssembly实现,你可能想在完成后手动调用Deno.exit(0)
, 以便你的代码在合理的时间内退出。
为什么这不推荐: Deno比node新,使用范围小,支持的平台比node少,所以推荐node作为主要运行esbuild的方式。 Deno还使用互联网作为包系统,而不是现有的JavaScript包生态系统, esbuild是为npm风格的包管理而设计和优化的。你应该仍然能够使用esbuild与Deno, 但如果你希望能够捆绑HTTP URL,则需要一个插件。
#从源代码构建
要构建esbuild的源代码:
- 安装Go编译器:
- 下载esbuild的源代码:
git clone --depth 1 --branch v0.25.5 https://github.com/evanw/esbuild.git cd esbuild
- 构建
esbuild
可执行文件(它将是esbuild.exe
在Windows上):go build ./cmd/esbuild
如果你想要为其他平台构建,你可以只在前缀构建命令中添加平台信息。例如,你可以使用此命令构建 32位Linux版本:
GOOS=linux GOARCH=386 go build ./cmd/esbuild
为什么这不推荐: 本机版本只能通过命令行界面使用,这对于复杂用例来说可能是不便的, 并且不支持插件。你需要编写JavaScript或Go代码并使用esbuild的API 使用插件。