前言
本篇文章接上文,通過嘗試使用esbuild的能力和業界的落地方案作為切入點繼續深入esbuild的原理。
嘗試Esbuild
ESBuild在API層面上非常簡潔, 主要的API隻有兩個: Transform和Build, 這兩個API可以通過CLI, JavaScript, Go的方式調用。
Transform主要用于對源代碼的轉換, 接受的輸入是字元串, 輸出的是轉換後的代碼
# 用CLI方式調用, 将ts代碼轉化為js代碼
echo 'let x: number = 1' | esbuild --loader=ts => let x = 1;
Build主要用于建構, 接受的輸入是單檔案或檔案集合
// 用JS模式調用build方法
require('esbuild').buildSync({
entryPoints: ['in.js'],
bundle: true,
outfile: 'out.js',
})
ESBuild的内容類型(Content Type)包括了ES在打包時可以解析的檔案類型, 這一點和Webpack的loader概念類似, 下面的例子是在打包時用JSX Loader解析JS檔案。
require('esbuild').buildSync({
entryPoints: ['app.js'],
bundle: true,
loader: {
'.js': 'jsx'
},
outfile: 'out.js',
})
借助esbuild的能力:如果你覺得目前完全使用ESBuild還不成熟, 也可以在Webpack體系中使用ESBuild的loader來替代babel用于進行代碼轉換, 除此之外, esbuild-loader[5]還可以用于JS & CSS的代碼最小化.
const { ESBuildMinifyPlugin } = require('esbuild-loader')
module.exports = {
rules: [{
test: /.js$/,
// 使用esbuild作為js/ts/jsx/tsx loader
loader: 'esbuild-loader',
options: {
loader: 'jsx',
target: 'es2015'
}
}, ],
// 或者使用esbuild-loader作為JS壓縮工具
optimization: {
minimizer: [
new ESBuildMinifyPlugin({
target: 'es2015'
})
]
}
}
注意:前面說過Esbuild轉換的代碼是無法降級到 ES5 及以下
使用 Esbuild 的虛拟子產品,可以完成很豐富的功能,比如子產品名當做一個函數來進行編譯,甚至可以在編譯階段實作函數遞歸的過程。比如這個 Esbuild 插件:
{
name: 'fibo',
setup(build) {
build.onResolve({
filter: /^fib\(\d+\)/
}, args = > {
return {
path: args.path,
namespace: 'fib'
}
}) build.onLoad({
filter: /^fib\(\d+\)/,
namespace: 'fib'
}, args = > {
const match = /^fib\((\d+)\)/.exec(args.path);
n = Number(match[1]);
console.log(n);
let contents = n < 2 ? `export
default $ {
n + 1
}` : `import n1 from 'fib(${n - 1})'
import n2 from 'fib(${n - 2})'
export
default n1 + n2`
return {
contents
}
})
}
}
引入這個插件,可以解析如下的 import 語句:
import fib5 from 'fib(5)' console.log(fib5) // 13
所有的子產品都是虛拟子產品,在真實檔案系統中并不存在,另外,還能借助虛拟子產品來進行 URL Import,支援如下的 import 代碼:
import React from 'https://esm.sh/[email protected]'
業界落地方案
1.代碼壓縮工具
Esbuild 有非常優秀的代碼壓縮能力,有着比傳統的壓縮工具一個量級以上的性能差距。Vite 在 2.6 版本也官宣在生産環境中直接使用 Esbuild 來壓縮 JS 和 CSS 代碼。
2.Bundler庫
Vite 中在開發階段使用 Esbuild 來進行依賴的預打包,将所有用到的第三方依賴轉成 ESM 格式 Bundle 産物,并且未來有用到生産環境的打算。
同時業界也有一些平台基于純 Esbuild 來做線上 cjs -> esm 的 CDN 服務,比如 esm.sh :
3.小程式編譯
對于小程式的場景,也可以使用 Esbuild 來代替 Webpack,大大提升編譯速度,對于 AST 的轉換則通過 Esbuild 插件嵌入 SWC 來實作,實作快速編譯。
4.Web建構
Web 場景就顯得比較複雜了,對于相容性和周邊工具生态的要求比較高,比如低浏覽器文法降級、CSS 預編譯器、HMR 等等,如果要用純 Esbuild 來做,還需要補充很多能力。
已有大佬基于 Esbuild 實作了一套 Web 開發腳手架 ewas,已經在 Github 開源,倉庫位址: https://github.com/sanyuan0704/ewas。
如今 Remix 1.0 正式釋出,底層使用 Esbuild 建構,帶來了極緻的性能體驗,成為 Next.js 強有力的競争對手。
但總體來說,目前 Esbuild 對于真實的 Web 場景還有很多能力不支援,還有一些硬傷,包括文法不支援降級到ES5,拆包不靈活、不支援 HMR,對于真正能作為 Webpack 一樣的建構工具來講還有很長的路要走。
總結
Esbuild的性能是其一大利器,這對于很多開發者和架構都會是一個優先考慮的因素,我們夜看到在整個生态系統中其也在慢慢的進行滲透,但就目前而言還不能完全替代Webpack等主流工具,畢竟整體生态環境有待完善。
建議如果想嘗試esbuild的能力,但已有的基礎設施穩定并且替換成本較大時, 可以嘗試漸進式的利用新工具(loader)或者Vite這種基于ESBuild二次封裝的建構工具。
歡迎各位coder關注微信公衆号,文章首發。