【總結】1248- 快速上手 Esbuild
相信很多小伙伴第一次使用 Vite 開發(fā)項目的時候,都會被它的速度震驚到。為什么 Vite 那么快呢?除了使用了 ES modules 之外,Vite 內(nèi)部還使用了一個神器 —— ?esbuild。
Esbuild 是由 Figma 聯(lián)合創(chuàng)始人 Evan Wallace 于 2020 年開發(fā)的工具。它是一個速度極快的 JavaScript/CSS 打包器,相比已有的 Web 構建工具,它的構建速度快 10-100 倍。

如此逆天的性能提升,還在抱怨 Webpack 打包慢的你,是不是很心動?心動不如行動,本文將帶你一起快速上手 esbuild。
安裝 esbuild
你可以通過 npm 來安裝 esbuild ,以下命令將以局部的方式來安裝 esbuild。當然你也可以使用 yarn 或 pnpm 等其它客戶端來安裝 esbuild。
?npm?install?esbuild?-D
待安裝成功后,可以運行以下命令來檢測是否安裝成功:
?./node_modules/.bin/esbuild?--version
當以上命令成功執(zhí)行后,終端會輸出當前的 esbuild 版本信息 —— 0.14.21。為了方便后面的演示,我們來新建一個 getting-started-esbuild 項目,然后使用 npm init -y 來初始化項目:
?mkdir?getting-started-esbuild
?npm?init?-y
Esbuild 支持 TypeScript 和 JSX 語法,下面我們先來體驗如何打包 TS 文件。
打包 TS
首先,在根目錄下新建一個 math.ts 文件并輸入以下內(nèi)容:
//?math.ts
export?const?add?=?(a:?number,?b:?number)?=>?a?+?b;
接著,繼續(xù)新建一個 main.ts 文件并輸入以下內(nèi)容:
//?main.ts
import?{?add?}?from?"./math"
console.log(`3?+?5?=?${add(3,?5)}`);
為了方便后續(xù)的打包操作,我們在 package.json ?文件的 scripts 字段中新增一個打包 TS 文件的命令:
{
??"name":?"getting-started-esbuild",
??"scripts":?{
????"build:ts":?"esbuild?main.ts?--bundle?--outfile=main.js"
??}
}
esbuild 默認不進行打包,所以你必須顯式設置
--bundle標志,而--outfile標志用于設置打包輸出的文件名稱。若未設置--outfile標志,esbuild 將把結果發(fā)送到標準輸出(stdout)。
之后,我們就可以通過 npm run build:ts 命令來打包 main.ts 文件。以下是經(jīng)過 esbuild 打包后的輸出結果:
//?main.js
(()?=>?{
??//?math.ts
??var?add?=?(a,?b)?=>?a?+?b;
??//?main.ts
??console.log(`3?+?5?=?${add(3,?5)}`);
})();
除了支持打包 TS 之外, esbuild 也支持打包 css 文件。下面我們來看一下如何利用 ?esbuild 打包 css 文件。
打包 CSS
首先,在根目錄下新建一個 normalize.css 文件并輸入以下內(nèi)容:
/**?normalize.css?*/
html?{
??line-height:?1.15;?/*?1?*/
??-webkit-text-size-adjust:?100%;?/*?2?*/
}
body?{
??margin:?0;
}
接著,繼續(xù)新建一個 style.css 文件并輸入以下內(nèi)容:
/**?style.css?*/
@import?"normalize.css";
p?{
??font-weight:?bold;
}
同樣,為了方便后續(xù)的打包操作,我們在 package.json ?文件的 scripts 字段中新增一個打包 CSS 文件的命令:
{
??"name":?"getting-started-esbuild",
??"scripts":?{
????"build:css":?"esbuild?style.css?--bundle?--minify?--outfile=
??????style.min.css"
??}
}
之后,我們就可以通過 npm run build:css 命令來打包 style.css 文件。以下是經(jīng)過 esbuild 打包后的輸出結果:
html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}p{font-weight:700}
打包圖片
在 Web 項目打包過程中,我們經(jīng)常需要處理圖片資源。esbuild 內(nèi)置了 dataurl 和 file 加載器,利用這些加載器我們就可以輕松處理圖片資源。
下面我們將使用 esbuild 的 logo 來演示一下如何打包圖片資源,為了驗證不同 loader,我們準備了 esbuild-logo.png 和 esbuild-logo.jpg 兩張不同格式的圖片文件:

準備好圖片資源文件之后,我們在根目錄下新建一個 index.html 文件并輸入以下內(nèi)容:
html>
<html?lang="zh-cn">
??<head>
????<meta?charset="UTF-8"?/>
????<meta?http-equiv="X-UA-Compatible"?content="IE=edge"?/>
????<meta?name="viewport"?content="width=device-width,?initial-scale=1.0"?/>
????<title>Getting?started?esbuildtitle>
??head>
??<body>
????<div?id="main">
??????<div>
????????<img?alt="esbuild-logo"?id="dataUrlLogo"?/>
??????div>
??????<div>
????????<img?alt="esbuild-logo"?id="urlLogo"?/>
??????div>
????div>
????<script?src="./index.js">script>
??body>
html>
接著,繼續(xù)新建一個 index.ts 文件并輸入以下內(nèi)容:
import?pngUrl?from?"./esbuild-logo.png";
const?dataUrlImg:?HTMLImageElement?=?document.querySelector("#dataUrlLogo");
dataUrlImg.src?=?pngUrl;
import?jpgUrl?from?"./esbuild-logo.jpg";
const?urlImg:?HTMLImageElement?=?document.querySelector("#urlLogo");
urlImg.src?=?jpgUrl;
然后,我們在 package.json ?文件的 scripts 字段中新增一個打包圖片資源的命令:
{
??"name":?"getting-started-esbuild",
??"scripts":?{
????"build:image":?"esbuild?index.ts?--bundle?--loader:.png=dataurl?
???????--loader:.jpg=file?--outfile=index.js"
??}
}
在以上的
build:image命令中,我們?yōu)?.png文件指定了dataurl加載器,為.jpg文件指定了file加載器。dataurl加載器會對圖片的二進制數(shù)據(jù)進行 base64 編碼,然后組裝成 data-uri 的形式。
之后,我們就可以通過 npm run build:image 命令來打包圖片資源文件。以下是經(jīng)過 esbuild 打包后的輸出結果:
(()?=>?{
??//?esbuild-logo.png
??var?esbuild_logo_default?=?"data:image/png;base64,iVBORw0KGgoAAAAN...=";
??//?esbuild-logo.jpg
??var?esbuild_logo_default2?=?"./esbuild-logo-WVOHGFM5.jpg";
??//?index.ts
??var?dataUrlImg?=?document.querySelector("#dataUrlLogo");
??dataUrlImg.src?=?esbuild_logo_default;
??var?urlImg?=?document.querySelector("#urlLogo");
??urlImg.src?=?esbuild_logo_default2;
})();
由于我們?yōu)?.png 文件指定了 dataurl 加載器,所以 esbuild-logo.png 文件的內(nèi)容就被轉化為 data-uri 的數(shù)據(jù)格式。
使用 build API
在前面的示例中,我們都是通過在命令行啟動 esbuild 應用程序來執(zhí)行打包操作。對于簡單的命令來說,這種方式很便捷。但如果我們的命令很復雜,比如需要設置較多的配置選項,那么我們的命令就不便于閱讀。針對這個問題,我們可以使用 esbuild 提供的 build api。
在 esbuild 模塊的入口文件 main.js 中,我們可以清楚地看到該模塊導出的內(nèi)容:
//?node_modules/esbuild/lib/main.js
0?&&?(module.exports?=?{
??analyzeMetafile,
??analyzeMetafileSync,
??build,
??buildSync,
??formatMessages,
??formatMessagesSync,
??initialize,
??serve,
??transform,
??transformSync,
??version
});
由以上代碼可知,esbuild 為我們提供了 build(異步) 和 buildSync(同步) 的 API。接下來,我們以異步的 build API 為例,來打包一下前面的 main.ts 文件。
為了方便管理項目的腳本,我們先在根目錄下新建一個 scripts 目錄,然后在該目錄下新建一個 build.js 文件并輸入以下內(nèi)容:
//?scripts/build.js
require("esbuild")
??.build({
????entryPoints:?["main.ts"],
????outfile:?"main.js",
????bundle:?true,
????loader:?{?".ts":?"ts"?},
??})
??.then(()?=>?console.log("??Done"))
??.catch(()?=>?process.exit(1));
創(chuàng)建完 build.js 文件之后,我們就可以在終端中執(zhí)行 node scripts/build.js 命令來執(zhí)行打包操作。
Watch Mode
在開發(fā)階段,我們希望當文件發(fā)生異動的時候,能自動執(zhí)行打包操作,從而生成新的文件。針對這種場景,可以在調用 build API 的時候,設置 watch 字段的值為 true。
//?scripts/watch-build.js
require("esbuild")
??.build({
????entryPoints:?["main.ts"],
????outfile:?"main.js",
????bundle:?true,
????loader:?{?".ts":?"ts"?},
?watch:?true,
??})
??.then(()?=>?console.log("??Done"))
??.catch(()?=>?process.exit(1));
Serve Mode
除了 Watch 模式之外,esbuild 還支持 Serve 模式。在該模式下,esbuild 將會根據(jù)用戶的配置啟動一個靜態(tài)資源服務器。當用戶在瀏覽器請求打包生成的文件時,若文件已經(jīng)發(fā)生變化,則 esbuild 會自動觸發(fā)打包操作并返回新的資源文件。
//?scripts/serve.js
require("esbuild")
??.serve(
????{
??????servedir:?"www",
??????port:?8000,
??????host:?"localhost"
????},
????{
??????entryPoints:?["index.ts"],
??????outdir:?"www",
??????bundle:?true,
??????loader:?{
????????".png":?"dataurl",
????????".jpg":?"file",
??????},
????}
??)
??.then((server)?=>?{
??????console.log("Server?is?running?at:?http://localhost:8000/")
????//?server.stop();
??});
使用插件
Esbuild 提供了很多開箱即用的功能,比如可以打包 TS、CSS 和 Image 等文件。但這還不能滿足我們?nèi)粘5墓ぷ餍枨蟆T谌粘9ぷ髦?,我們可能還需要打包 Sass、Less、Yaml 或 Markdown 等文件。
為了解決上述的問題,從而滿足不同的使用場景,esbuild 設計了插件機制。利用 esbuild 提供的插件機制,開發(fā)者可以根據(jù)自己的需求,定制對應的插件,來實現(xiàn)對應的功能。當然你并不需要從頭開發(fā)各種插件,在開發(fā)對應的插件前,大家可以先瀏覽已有的社區(qū)插件。
使用 esbuild 插件,主要分為 2 個步驟:安裝插件和注冊插件。這里我們來介紹一下如何使用 esbuild-plugin-less 插件。
步驟一:安裝插件
?npm?install?esbuild-plugin-less?-D
步驟二:注冊插件
import?{?build?}?from?'esbuild';
import?{?lessLoader?}?from?'esbuild-plugin-less';
build({
??entryPoints:?[path.resolve(__dirname,?'index.ts')],
??bundle:?true,
??outdir:?path.resolve(__dirname,?'output'),
??plugins:?[lessLoader()],
??loader:?{
????'.ts':?'ts',
??},
});
在以上代碼中,我們通過 plugins 字段來注冊 esbuild-plugin-less 插件,之后 esbuild 就可以打包 less 文件了。如果使用的是 Sass 的話,就需要安裝 esbuild-plugin-sass 插件。
好的,esbuild 的相關內(nèi)容就介紹到這里,想系統(tǒng)學習 esbuild 的話,可以閱讀 esbuild 官方文檔。另外,如果想進一步了解它在實際工作中的應用,可以閱讀 又一個基于 Esbuild 的神器 這篇文章。

回復“加群”與大佬們一起交流學習~
點擊“閱讀原文”查看 130+ 篇原創(chuàng)文章
