快速上手 Esbuild

相信很多小夥伴第一次使用 Vite 開發項目的時候,都會被它的速度震驚到。爲什麼 Vite 那麼快呢?除了使用了 ES modules 之外,Vite 內部還使用了一個神器 ——  esbuild。

Esbuild 是由 Figma 聯合創始人 Evan Wallace 於 2020 年開發的工具。它是一個速度極快的 JavaScript/CSS 打包器,相比已有的 Web 構建工具,它的構建速度快 10-100 倍。

如此逆天的性能提升,還在抱怨 Webpack 打包慢的你,是不是很心動?心動不如行動,本文將帶你一起快速上手 esbuild。

安裝 esbuild

你可以通過 npm 來安裝 esbuild ,以下命令將以局部的方式來安裝 esbuild。當然你也可以使用 yarnpnpm 等其它客戶端來安裝 esbuild。

 npm install esbuild -D

待安裝成功後,可以運行以下命令來檢測是否安裝成功:

 ./node_modules/.bin/esbuild --version

當以上命令成功執行後,終端會輸出當前的 esbuild 版本信息 —— 0.14.21。爲了方便後面的演示,我們來新建一個 getting-started-esbuild 項目,然後使用 npm init -y 來初始化項目:

 mkdir getting-started-esbuild
 npm init -y

Esbuild 支持 TypeScript 和 JSX 語法,下面我們先來體驗如何打包 TS 文件。

打包 TS

首先,在根目錄下新建一個 math.ts 文件並輸入以下內容:

// math.ts
export const add = (a: number, b: number) => a + b;

接着,繼續新建一個 main.ts 文件並輸入以下內容:

// main.ts
import { add } from "./math"

console.log(`3 + 5 = ${add(3, 5)}`);

爲了方便後續的打包操作,我們在 package.json  文件的 scripts 字段中新增一個打包 TS 文件的命令:

{
  "name""getting-started-esbuild",
  "scripts"{
    "build:ts""esbuild main.ts --bundle --outfile=main.js"
  }
}

esbuild 默認不進行打包,所以你必須顯式設置 --bundle 標誌,而 --outfile 標誌用於設置打包輸出的文件名稱。若未設置 --outfile 標誌,esbuild 將把結果發送到標準輸出(stdout)。

之後,我們就可以通過 npm run build:ts 命令來打包 main.ts 文件。以下是經過 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 文件並輸入以下內容:

/** normalize.css */
html {
  line-height: 1.15; /* 1 */
  -webkit-text-size-adjust: 100%; /* 2 */
}

body {
  margin: 0;
}

接着,繼續新建一個 style.css 文件並輸入以下內容:

/** style.css */
@import "normalize.css";{
  font-weight: bold;
}

同樣,爲了方便後續的打包操作,我們在 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 文件。以下是經過 esbuild 打包後的輸出結果:

html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}p{font-weight:700}

打包圖片

在 Web 項目打包過程中,我們經常需要處理圖片資源。esbuild 內置了 dataurlfile 加載器,利用這些加載器我們就可以輕鬆處理圖片資源。

下面我們將使用 esbuild 的 logo 來演示一下如何打包圖片資源,爲了驗證不同 loader,我們準備了 esbuild-logo.pngesbuild-logo.jpg 兩張不同格式的圖片文件:

準備好圖片資源文件之後,我們在根目錄下新建一個 index.html 文件並輸入以下內容:

<!DOCTYPE html>
<html lang="zh-cn">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta  />
    <title>Getting started esbuild</title>
  </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>

接着,繼續新建一個 index.ts 文件並輸入以下內容:

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 命令中,我們爲 .png 文件指定了 dataurl 加載器,爲 .jpg 文件指定了 file 加載器。dataurl 加載器會對圖片的二進制數據進行 base64 編碼,然後組裝成 data-uri 的形式。

之後,我們就可以通過 npm run build:image 命令來打包圖片資源文件。以下是經過 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;
})();

由於我們爲 .png 文件指定了 dataurl 加載器,所以 esbuild-logo.png 文件的內容就被轉化爲 data-uri 的數據格式。

使用 build API

在前面的示例中,我們都是通過在命令行啓動 esbuild 應用程序來執行打包操作。對於簡單的命令來說,這種方式很便捷。但如果我們的命令很複雜,比如需要設置較多的配置選項,那麼我們的命令就不便於閱讀。針對這個問題,我們可以使用 esbuild 提供的 build api。

在 esbuild 模塊的入口文件 main.js 中,我們可以清楚地看到該模塊導出的內容:

// 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 文件並輸入以下內容:

// 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));

創建完 build.js 文件之後,我們就可以在終端中執行 node scripts/build.js 命令來執行打包操作。

Watch Mode

在開發階段,我們希望當文件發生異動的時候,能自動執行打包操作,從而生成新的文件。針對這種場景,可以在調用 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 將會根據用戶的配置啓動一個靜態資源服務器。當用戶在瀏覽器請求打包生成的文件時,若文件已經發生變化,則 esbuild 會自動觸發打包操作並返回新的資源文件。

// 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 等文件。但這還不能滿足我們日常的工作需求。在日常工作中,我們可能還需要打包 Sass、Less、Yaml 或 Markdown 等文件。

爲了解決上述的問題,從而滿足不同的使用場景,esbuild 設計了插件機制。利用 esbuild 提供的插件機制,開發者可以根據自己的需求,定製對應的插件,來實現對應的功能。當然你並不需要從頭開發各種插件,在開發對應的插件前,大家可以先瀏覽已有的社區插件。

使用 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 的相關內容就介紹到這裏,想系統學習 esbuild 的話,可以閱讀 esbuild 官方文檔。另外,如果想進一步瞭解它在實際工作中的應用,可以閱讀 又一個基於 Esbuild 的神器 這篇文章。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/ZO44ibIzfDPVBpmCpiZBMw