esbuild 是一个快速的 JavaScript 打包器,主要目标是带来构建工具性能的新时代,并在此过程中创建易于使用的现代捆绑器。

esbuild 是一个用 Go 编写的快速而简单的 JavaScript 捆绑包,其主要特点有:

以上是 esbuild 官方对该项目的一些介绍。

本文将介绍 esbuild 的一些基本的用法,如何捆绑 JavaScript 应用程序,包括 TypeScript、图像文件、CSS 等。

安装 esbuild

首先,使用 npm 安装 esbuild:

$ npm i -g esbuild

然后,您可以通过调用 esbuild 命令来验证是否安装成功:

$ esbuild --version
# 0.14.38

如果您不想在全局范围内安装 esbuild,也可以这样做:

$ npm i esbuild

但您必须使用完整路径调用 esbuild:

$ ./node_modules/.bin/esbuild --version
# 0.14.38

使用 esbuild 捆绑 TypeScript

创建一个 main.ts 文件,其中有如下内容:

let message: string = 'Hello esbuild!'
console.log(message)

通过 CLI 捆绑 TypeScript 代码:

$ esbuild main.ts --outfile=output.js --bundle --loader:.ts=ts
  output.js  87b 

Done in 4ms

esbuild 命令接受 main.ts 作为入口,它是应用程序启动的地方。

然后,提供 outfile 选项作为定义输出文件的方法。如果不提供此选项,esbuild 会将结果发送到 stdout

loader 选项是用于加载 TypeScript 文件扩展名的选项。但是,您可以忽略此选项,因为 esbuild 可以根据文件扩展名决定使用哪个 loader

通过 bundle 选项,esbuild 将把所有依赖项内联到 output.js 文件中。

运行命令后,将捆绑到 output.js 文件,内容如下:

(() => {
  // main.ts
  var message = "Hello esbuild!";
  console.log(message);
})();

我们来看一下不使用 bundle 选项的情况。

我们更改 main.ts 文件的内容如下:

import { sayHello } from './lib'

SayHello()

在创建 lib.ts 文件,其中编写一个 sayHello 并导出:

export function sayHello() {
  console.log('Hello esbuild!')
}

如果不使用 bundle 选项,esbuild 只会在结果中导入依赖项:

$ esbuild main.ts
import { sayHello } from "./lib";
sayHello();

但如果使用 bundle 选项,esbuild 将在结果中内联 lib.ts 的内容:

$ esbuild main.ts --bundle
(() => {
  // lib.ts
  function sayHello() {
    console.log("Hello esbuild!");
  }

  // main.ts
  sayHello()
})();

使用 bundle 选项,可以将所有代码打包到一个文件中。换句话说,两个文件变成一个文件。

使用 esbuild 捆绑 React

使用 esbuild 集成 React 到项目中及极其简单。

首先,使用 npm 安装 React 库:

$ npm i react react - dom

然后创建一个名为 App.js 的文件,添加以下内容:

import React from 'react'
import ReactDOM from 'react-dom'

function App() {
  return <div>Hello esbuild!</div>
}

ReactDOM.render(<App />, document.getElementById('root'))

创建一个 HTML 文件,以便 React 可以将您的应用程序渲染到具有 ID 为 rootdiv 中。将以下代码添加到 index.html 文件中:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
    <title>Hello esbuild!</title>
  </head>

  <body>
    <div id="root"></div>
    <script src="AppBundle.js"></script>
  </body>
</html>

在 HTML 文件中,我们使用 AppBundle.js 这是捆绑的 JavaScript 文件的名称。

$ esbuild App.js --bundle --outfile=AppBundle.js --loader:.js=jsx

我们使用 bundle 选项绑定 JavaScript 文件。然后,使用 outfile 选项为输出文件指定所需的名称。

最后一个选项 loader 实际上不是可选的。告诉 esbuild 对带有 .js 扩展名的文件使用 JSX 加载器,因为 JSX 语法在 App.js 中。如果不使用 JSX 加载器,esbuild 将抛出一个错误。如果输入文件的扩展名是 .jsx 而不是 .js,可以省略 loader 选项。因此,如果你将 JavaScript 文件命名为 App.jsx,那么你可以忽略 loader 选项。

现在您有了 AppBundle.js,让我们打开 index.html 来检查您的绑定过程是否正常工作。

这里我们需要通过 server 的方式打开 index.html,推荐 VSCode 插件 Live Server,也可以使用 http-server 模块,我们也会在下面介绍到 esbuild 的 serve 模式,来开启一个 server。

Hello esbuild

将 CSS 与 esbuild 捆绑

假设我们的 color.css 文件有以下内容:

.item {
  color: plum;
}

创建 style.css 导入 color.css

@import 'color.css';

p {
  font-weight: bold;
}

要捆绑这两个 CSS 文件,可以运行如下 esbuild 命令:

$ esbuild style.css --outfile=out.css --bundle

  out.css  85b 

Done in 5ms

查看 out.css 文件:

/* color.css */
.item {
  color: plum;
}

/* style.css */
p {
  font-weight: bold;
}

现在,您只需要在 HTML 文件中包含该文件即可。

如果您想要压缩文件,可以使用 --minify 选项:

$ esbuild style.css --outfile=out.css --bundle --minify

  out.css  36b 

Done in 7ms

压缩后的内容如下:

.item{color:plum}p{font-weight:700}

捆绑图像

您还可以将图像与 esbuild 捆绑在一起。

捆绑图像有两种选择:

  • 将图像作为外部文件加载到 JavaScript 文件中
  • 将图像作为 Base64 编码的 Data URL 嵌入到 JavaScript 文件中

让我们看看两者的区别。

创建一个 index.html 文件,并添加以下内容:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>Hello, esbuild!</title>
</head>

<body>
  <div id="root">
    <div>
      <img id="image_png" />
    </div>
    <div>
      <img id="image_jpg" />
    </div>
  </div>
  <script src="out_main.js"></script>
</body>

</html>

然后,创建一个 main.js 文件,并添加以下内容:

import png_url from './example.png'
const png_image = document.getElementById('image_png')
png_image.src = png_url

import jpg_url from './baidu.jpg'
const jpg_image = document.getElementById('image_jpg')
jpg_image.src = jpg_url

这里,我们使用 JavaScript 文件中的 import 语句加载图像。与绑定 CSS 文件不同,您不直接绑定图像,而是通过绑定引用图像的 JavaScript 文件来绑定图像。

现在,打包 JavaScript 文件:

$ esbuild main.js --bundle --loader:.png=dataurl --loader:.jpg=file --outfile=out_main.js

  out_main.js         102.7kb
  baidu-YKEFL4XA.jpg   76.8kb

Done in 15ms

这里使用了两个 loader.png 扩展使用 dataurl.jpg 扩展使用 file 。使用 file 加载器的将会生成一个 baidu-YKEFL4XA.jpg 的新文件。

查看生成的 out_main.js 文件,内容如下:

(() => {
  // example.png
  var example_default = "data:image/png;base64,iVBORw0K...";

  // baidu.jpg
  var baidu_default = "./baidu-YKEFL4XA.jpg";

  // main.js
  var png_image = document.getElementById("image_png");
  png_image.src = example_default;
  var jpg_image = document.getElementById("image_jpg");
  jpg_image.src = baidu_default;
})();

正如您所看到的,第一张图片使用 Based64 编码的 Data URL 格式。第二个图像使用文件路径格式。对于第二张图片,还有一个名为 baidu-YKEFL4XA.jpg 的外部文件。

最后,通过 server 的方式打开 index.html,查看效果。

使用插件

esbuild 并不是一个完整的捆绑解决方案。它默认支持 React、CSS 和图像,但不支持 SASS 预处理等器。如果你想捆绑 SASS 文件,则需要安装一个 esbuild 插件。

esbuild 插件列表

有几个插件可以捆绑 SASS 文件。这里使用我们 esbuild-plugin-sass

使用 npm 安装插件,如下所示:

$ npm install esbuild-plugin-sass -D

我们在 style.scss 文件内编写一些简单的样式:

// style.scss
$font: Roboto;
$color: plum;

#root {
  font: 1.2em $font;
  color: $color;
}

要使用 esbuild-plugin-sass 插件,需要使用 esbuild 的 build API。

main.js 添加以下内容:

const sassPlugin = require('esbuild-plugin-sass')

require('esbuild')
  .build({
    entryPoints: ['style.scss'],
    outfile: 'bundle.css',
    bundle: true,
    plugins: [sassPlugin()]
  })
  .then(() => console.log('Done'))
  .catch(() => process.exit(1))

我们使用 plugins 来引用 SASS 插件,entryPoints 引用是我们编写的 scss 文件,其返回的是一个 Promise,成功后我们输出 Done

执行 main.js 文件:

$ node main.js
Done

您可以打开 bundle.css 文件检查输出结果:

/* ../../temp/tmp-10260-4kl4Lq4Efuiv/esbuild-test/style.css */
#root {
  font: 1.2em Roboto;
  color: plum;
}

watch 模式

esbuild 的 watch 模式会监听入口文件,并自动打包。

我们监听 main.ts 文件,如果其中内容存在变动,将自动重新打包:

// build.js
require('esbuild')
  .build({
    entryPoints: ['main.ts'],
    outfile: 'output.js',
    bundle: true,
    loader: { '.ts': 'ts' },
    watch: true
  })
  .then(() => console.log('Done'))
  .catch(() => process.exit(1))

mian.ts 文件的内容如下:

let message: string = 'Hello esbuild!'
console.log(message)

现在,我们执行 build.js 文件:

$ node build.js

你可能会注意,构建的过程并未中断,仍处于活动状态,esbuild 会持续监听 mian.ts 文件的变动。

我们先查看 output.js 文件:

(() => {
  // main.ts
  var message = "Hello esbuild!";
  console.log(message);
})();

回到 main.ts 文件,修改一些内容:

let message: string = 'Hello World!'
console.log(message)

在查看 output.js

(() => {
  // main.ts
  var message = "Hello World!";
  console.log(message);
})();

可以看到输出的文件会自动更新。

watch 可以监视文件系统,以便 esbuild 在检测到文件更改时可以捆绑输入文件。

serve 模式

还有另一种自动绑定文件的方法,称为 serve 模式。这意味着您要启动一台服务器来为输出文件提供服务。如果有人从浏览器请求输出文件,如果文件已更改,服务器将自动绑定输入文件。

以下是一个 index.html 内容:

<!DOCTYPE html>
<html lang="en">
  <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>Hello esbuild!</title>
  </head>
  <body>
    <script src="output.js"></script>
  </body>
</html>

其中引入了 main.ts 捆绑后输出的 output.jsmain.ts 文件内容如下:

let message: string = 'Hello esbuild!'
console.log(message)

我们使用 serve 模式捆绑文件:

$ esbuild main.ts --outfile=output.js --bundle --loader:.ts=ts --serve=localhost:8000 --servedir=.

> Local: http://127.0.0.1:8000/

serve 选项用于定义服务器和端口。servedir 选项定义服务器服务的目录。

访问 http://127.0.0.1:8000,打开控制台查看输入内容。然后尝试着修改 main.ts 的内容,刷新页面查看修改后的内容。

最后

本文简单介绍 esbuild 的一些基本用法,例如 sourcemap 等我们是没讲到的,详细内容可以查看文档,后面学习过程中也会进行总结。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐