開始使用
#安裝 esbuild
首先,下載並在本地安裝 esbuild 指令。可以使用 npm 安裝預先建置的原生可執行檔(當你安裝 node JavaScript 執行環境時會自動安裝)
npm install --save-exact --save-dev esbuild
這應該會在你的本地 node_modules
資料夾中安裝 esbuild。你可以執行 esbuild 可執行檔來驗證一切是否運作正常
./node_modules/.bin/esbuild --version
.\node_modules\.bin\esbuild --version
建議使用 npm 安裝原生可執行檔來安裝 esbuild。但如果你不想這樣做,還有一些 其他安裝方式。
#你的第一個套件
以下是一個 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 編寫 JavaScript 建立腳本。它可能看起來像這樣(請注意,此程式碼必須儲存在副檔名為 .mjs
的檔案中,因為它使用 import
關鍵字)
import * as esbuild from 'esbuild'
await esbuild.build({
entryPoints: ['app.jsx'],
bundle: true,
outfile: 'out.js',
})
build
函式會在子處理序中執行 esbuild 可執行檔,並傳回一個承諾,在建立完成時解析。還有一個非同步的 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 功能。
#針對節點進行打包
即使在使用節點時不需要打包器,但在節點中執行程式碼之前,有時仍可以受益於使用 esbuild 處理您的程式碼。打包可以自動移除 TypeScript 型別,將 ECMAScript 模組語法轉換為 CommonJS,並將較新的 JavaScript 語法轉換為特定節點版本的較舊語法。在發佈套件之前,打包套件可能是有益的,這樣可以減少下載大小,並在載入時減少從檔案系統讀取的時間。
如果您要打包將在節點中執行的程式碼,則應透過將 --platform=
傳遞給 esbuild 來組態 platform 設定。這會同時將一些不同的設定變更為對節點友善的預設值。例如,所有內建於節點的套件(例如 fs
)都會自動標記為外部,因此 esbuild 不會嘗試將它們打包。此設定也會停用對 package.json
中 browser 欄位的詮釋。
如果您的程式碼使用較新的 JavaScript 語法,而您的節點版本不支援,您將需要組態節點的 target 版本
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 來打包您的相依性。有許多 esbuild 在打包時不支援的節點特定功能,例如 __dirname
、import.meta.url
、fs.readFileSync
和 *.node
原生二進位模組。您可以透過將 packages 設定為 external 來從套件中排除所有相依性
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
。
然而,人們有時會因為在 Windows 或 macOS 上安裝 esbuild,然後將其 node_modules
目錄複製到執行 Linux 的 Docker 映像中,或在 Windows 和 WSL 環境之間複製其 node_modules
目錄而陷入此情況。讓此情況正常運作的方法取決於您的套件管理員
npm/pnpm:如果您使用 npm 或 pnpm 安裝,您可以在複製檔案時嘗試不複製
node_modules
目錄,並在複製後於目標平台上執行npm ci
或npm install
。或者,您可以考慮改用 Yarn,它內建支援同時在多個平台上安裝套件。Yarn:如果您使用 Yarn 安裝,您可以嘗試在
.yarnrc.yml
檔案中使用supportedArchitectures
功能,同時列出此平台和其他平台。請記住,這表示檔案系統上會存在多個 esbuild 副本。
如果您使用 ARM 版本的 npm 安裝 esbuild,但隨後嘗試使用在 Rosetta 中執行的 x86-64 版本的 node 來執行 esbuild,您也可能會在配備 ARM 處理器的 macOS 電腦上陷入此情況。在這種情況下,一個簡單的解決方法是改用 ARM 版本的 node 執行您的程式碼,您可以在此處下載:https://node.dev.org.tw/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(即不使用 yarn esbuild
)的情況下執行 esbuild。這可能會讓 esbuild 執行速度快 10 倍。
#其他安裝方式
安裝 esbuild 的建議方式是 使用 npm 安裝原生可執行檔。但您也可以使用以下方式安裝 esbuild
#下載組建
如果您有 Unix 系統,可以使用以下命令下載適用於您當前平台的 esbuild
二進制可執行檔(它將下載到當前工作目錄)
curl -fsSL https://esbuild.dev.org.tw/dl/v0.20.1 | sh
您也可以使用 latest
而不是版本號碼來下載最新版本的 esbuild
curl -fsSL https://esbuild.dev.org.tw/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.20.1.tgz tar xzf ./darwin-x64-0.20.1.tgz ./package/bin/esbuild Usage: esbuild [options] [entry points] ...
@esbuild/darwin-x64
套件中的原生可執行檔適用於 macOS 作業系統和 64 位元 Intel 架構。在撰寫本文時,這是 esbuild 支援的平台的原生可執行檔套件的完整清單
套件名稱 | 作業系統 | 架構 | 下載 |
---|---|---|---|
@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-x64 |
netbsd 1 |
x64 |
|
@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 系統,因此在 Windows 上需要 WSL。另一個缺點是您無法將 外掛程式 與 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 版本還排除了一些功能,例如本機檔案伺服器。只有在沒有其他選擇時,例如當您想在不受支援的平台上使用 esbuild 時,您才應該這樣使用 WebAssembly 套件。WebAssembly 套件主要僅供 在瀏覽器中 使用。
#使用 Deno 取代 node
如果您想使用 esbuild 取代 Deno,那麼對於 Deno JavaScript 環境也有基本支援。該套件託管在 https://deno.land/x/esbuild 並使用原生 esbuild 可執行檔。可執行檔將在執行時從 npm 下載並快取,因此您的電腦需要網路存取權限才能存取 registry.npmjs.org 以使用此套件。使用套件的方式如下
import * as esbuild from 'https://deno.land/x/esbuild@v0.20.1/mod.js'
let ts = 'let test: boolean = true'
let result = await esbuild.transform(ts, { loader: 'ts' })
console.log('result:', result)
await esbuild.stop()
它的 API 與 esbuild 的 npm 套件基本上相同,但有一個新增功能:您需要在完成後呼叫 stop()
,因為與 node 不同,Deno 沒有提供必要的 API 來允許 Deno 在 esbuild 的內部子處理程序仍在執行時退出。
如果您想使用 esbuild 的 WebAssembly 實作,而不是 esbuild 的原生實作與 Deno,您可以透過匯入 wasm.js
而不是 mod.js
來執行,如下所示
import * as esbuild from 'https://deno.land/x/esbuild@v0.20.1/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
權限,且在檔案系統不可用(例如使用 Deno Deploy)的情況下,WebAssembly 是唯一選項。不過,請注意 esbuild 的 WebAssembly 版本比原生版本慢很多。關於 WebAssembly 的另一件事是,Deno 目前有一個錯誤,在所有載入的 WebAssembly 模組完全最佳化之前,處理程序終止會不必要地延遲,這可能需要數秒。如果您撰寫的是使用 esbuild 的 WebAssembly 實作的短暫腳本,您可能希望在程式碼執行完畢後手動呼叫 Deno.exit(0)
,讓您的程式碼在合理的時間內結束。
不建議這樣做的原因:Deno 比 node 新,使用較不廣泛,且支援的平台比 node 少,因此建議使用 node 作為執行 esbuild 的主要方式。Deno 也使用網際網路作為套件系統,而不是現有的 JavaScript 套件生態系統,而 esbuild 是針對 npm 式套件管理設計和最佳化的。您仍然可以使用 Deno 使用 esbuild,但如果您想要能夠綑綁 HTTP URL,您將需要外掛程式。
#從原始碼建置
從原始碼建置 esbuild
- 安裝 Go 編譯器
- 下載 esbuild 的原始碼
git clone --depth 1 --branch v0.20.1 https://github.com/evanw/esbuild.git cd esbuild
- 建置
esbuild
可執行檔(在 Windows 上將會是esbuild.exe
)go build ./cmd/esbuild
如果您想要建置其他平台,您只要在建置指令前加上平台資訊即可。例如,您可以使用這個指令建置 32 位元 Linux 版本
GOOS=linux GOARCH=386 go build ./cmd/esbuild
不建議這樣做的原因:原生版本只能透過命令列介面使用,這對於複雜的使用案例來說可能不符合人體工學,且不支援 外掛程式。您需要撰寫 JavaScript 或 Go 程式碼並使用 esbuild 的 API 才能使用外掛程式。