esbuild官方文档入门

1,686 阅读5分钟

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

前言

esbuild是面向未来的前端打包工具,让我们从官方文档开始一起学习。 esbuild.github.io

简介

image.png

访问首页,会显示使用esbuild打包three.js这个库所使用的时间与当下流行打包工具parcel2rollup + terserwebpack 5的对比。从统计图可以轻易看出esbuild有很明显的速度优势(10-100倍)。

为什么会这么快?

esbuild使用go语言来编写,运行时AOT对比JITJavaScript,有着无需编译的速度优势。并且go有着运行时占用内存少,能充分利用宿主CPU、多线程、内存共享等特征优势。

开始使用

根据官网,先从安装开始 esbuild.github.io/getting-sta…

安装

在控制台支持node命令的前提下执行:

npm install esbuild

上述命令是针对控制台当前路径项目安装,而非全局安装。

安装完成后尝试执行esbuild

./node_modules/.bin/esbuild --version

输出:

0.14.20

是目前esbuild发布在npm最新的稳定版本号。

打包试验

继续在当前项目做尝试,安装reactreact-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

输出:

image.png

当前项目文件内容:

image.png

out.js为什么这么大?

out.js内容就不贴出来了,主要是因为esbuildreactreact-dom两个依赖的代码都打包进去了,所以才这么大。

也正因为这样,out.js是可以单独拿出来执行的,无需额外安装依赖。

可以把out.js拷贝出来放到任意目录,然后对应控制台执行:

node out.js

输出:

<h1 data-reactroot="">Hello, world!</h1>

🤔,这不就是ssr吗!

npm script 配置

每次都用./node_modules/.bin/esbuild使用esbuild太麻烦了,优先使用node_modules/bin目录作为环境变量,本来就是npm script该干的事情啊。

在项目package.json加入以下脚本:

{
  "scripts": {
    "build": "esbuild app.jsx --bundle --outfile=out.js"
  }
}

然后控制台执行:

npm run build

😊一样能生成出打包后的产物out.js

除了使用命令行外,esbuild还提供build等其他api方法,供在nodejs运行时中打包使用。

项目根路径创建esbuild.js,内容如下:

require('esbuild').build({
  entryPoints: ['app.jsx'],
  bundle: true,
  outfile: 'out.js',
}).catch(() => process.exit(1))

然后控制台执行:

node esbuild.js

🥸一样能生成出打包后的产物out.js

定制浏览器运行产物

说在前面,esbuild目前官方是尚不支持将 ES6+ 语法转换为 ES5,有兼容ie11Android4.4.4Opera Mini的同学,可能需要额外用babel或者swc等工具先对源码做一下目标浏览器的polyfill

--minify

生产环境使用,用于压缩混淆产物代码。我们基于package.json基础上新增npm script

"build:min": "esbuild app.jsx --bundle --outfile=out.js --minify"

然后,控制台执行

npm run build:min

输出:

image.png

--sourcemap

一般开发时需要,生成sourcemap。

打包时候额外生成out.js.map,并在out.js末尾追加:

//# sourceMappingURL=out.js.map

--watch

一般开发时需要,输入文件变化自动重新执行命令行。

--target

esbuild 支持所有现代 JavaScript 语法。但是,较旧的浏览器可能不支持较新的语法,因此您可能需要配置target选项来告诉 esbuild 将较新的语法适当地转换为较旧的语法。

  • 这些语法功能总是针对旧版浏览器进行转换:
语法转换语言版本例子
函数参数列表和调用中的尾随逗号es2017foo(a, b, )
数字分隔符esnext1_000_000
  • 根据配置的语言目标,这些语法功能会针对旧版浏览器进行有条件的转换:
语法转换转换时--target低于例子
幂运算符es2016a ** b
异步函数es2017async () => {}
传播属性es2018let x = {...y}
休息属性es2018let {...x} = y
可选的捕获绑定es2019try {} catch {}
可选链接es2020a?.b
无效合并es2020a ?? b
import.metaes2020import.meta
逻辑赋值运算符es2021a ??= b
类实例字段esnextclass { x }
静态类字段esnextclass { static x }
私有实例方法esnextclass { #x() {} }
私有实例字段esnextclass { #x }
私有静态方法esnextclass { static #x() {} }
私有静态字段esnextclass { static #x }
符合人体工程学的品牌检查esnext#x in y
导入断言esnextimport "x" assert {}
类静态块esnextclass { static {} }
  • 这些语法特征目前总是通过未转换的:
语法转换--target低于时不支持例子
异步迭代es2018for await (let x of y) {}
异步生成器es2018async function* foo() {}
大整数es2020123n
Hashbang 语法esnext#!/usr/bin/env node
顶级等待esnextawait import(x)
任意模块命名空间标识符esnextexport {foo as 'f o o'}

API

esbuildAPI可以通过三种方式调用:命令行、JavaScript 和 Go。

esbuild有两个主要的APItransformbuild。了解应使用哪一个很重要,因为它们的工作方式不同。

Transform API

transform API是纯字符串操作的API,它的输入输出都是字符串。无需文件系统支持,适合用在工具链之中。

如 使用node命令行交互输入:

require('esbuild').transformSync('let x: number = 1', { loader: 'ts', })

输出:

image.png

Build API

build API是文件操作的API,传入单个或多个文件路径,输出单个或多个产物文件。

如 创建in.ts内容如下:

let x: number = 1

然后控制台执行以下命令行:

./node_modules/.bin/esbuild in.ts --outfile=out.js

生成out.js内容如下:

let x = 1;

同样,也可以使用node命令行交互

require('esbuild').buildSync({ entryPoints: ['in.ts'], outfile: 'out.js', })

也是会生成一样内容的out.js

支持内容

目前esbuild 默认loader支持的文件内容格式有:

  • JavaScript: .js .cjs .mjs
  • JSX: .jsx
  • TypeScript: .ts .tsx .cts .mts
  • JSON: .json
  • CSS: .css
  • TEXT: .txt

插件

最后是插件部分,目前官方解释该部分还是试验阶段,有可能发生重大变化,就不一一细说了,HHH😂。有兴趣的伙伴请见 esbuild.github.io/plugins/

image.png

总结

前端工具链内卷越发激烈,最近esbuild swc热起,使用go rust对传统编译工具(babel)发起了降维打击。且越发成熟,大有取代趋势。搬砖之余需要多多观望与了解。期待后续深度内容,😚感谢阅读。