Vite 是怎樣利用 Esbuild 來提升性能的 ?

前言

在上一篇 爲什麼有人說 vite 快,有人卻說 vite 慢?[1] 中,我們提到過開發模式下使用 Vite 會有首屏性能下降的負面效果。之所以會造成首屏性能下降,一方面是 dev server 需要完成預構建纔可以響應首屏請求;另一方面是需要對請求文件做實時轉換。

也許有的同學會問,是不是針對這兩個方面做優化,就可以提升首屏性能呢?原則上這樣是沒有問題的,而且 Vite 也是這麼做的。爲了能提升性能,Vite 另闢蹊徑的藉助了 Esbuild 能快速完成項目打包、文件轉換的能力來進行預構建、內容轉換,效果非常好。

今天小編就通過本文和大家一起聊一聊 Vite 是怎樣利用 Esbuild 來提升性能的。

初探 Esbuild

首先,小編先帶大家簡單瞭解一下 Esbuild,其官方地址是: Esbuild[9]

什麼是 Esbuild

Esbuild 是一款基於 Go 語言開發的 javascript 打包工具,最大的一個特徵就是快。

通過官網提供的一張圖,我們可以清晰的看到 Esbuild 的表現是多麼優秀:

同樣規模的項目,使用 Esbuild 可以將打包速度提升 10 - 100 倍,這對廣大一直飽受 Webpack 緩慢打包速度折磨的開發人員來說,簡直就是福音。

Esbuild 之所以能這麼快,主要原因有兩個:

關鍵 API - transfrom & build

Esbuild 並不複雜。它對外提供了兩個 API - transformbuild,使用起來非常簡單。

transfrom,轉換的意思。通過這個 api,我們可以將 tsjsxtsx 等格式的內容轉化爲 jstransfrom 只負責文件內容轉換,並不會生成一個新的文件。

build,構建的意思,根據指定的單個或者多個入口,分析依賴,並使用 loader 將不同格式的內容轉化爲 js 內容,生成一個或多個 bundle 文件。

這兩個 API 的使用方式:

const res = await esbuild.transform(code, options) // 將 code 轉換爲指定格式的內容

esbuild.build(options) // 打包構建
複製代碼

關於使用 transformbuild 需要傳入的具體配置項,本文就不詳細說明了,官網對這一塊兒有很詳細的說明,感興趣的同學可以去官網 - simple-options[11]Advanced options[12] 看看,也可以自己動手試試。

plugin

WebpackRollup 等構建工具一樣,Esbuild 也提供了供外部使用的 plugin,使得我們可以介入構建打包過程。

在這裏要說明一點,只有 build 這個 API 的入參中可以配置 plugintransform 不可以。

一個標準的 plugin 的標準格式如下:

let customerPlugin = {
    name: 'xxx',
    setup: (build) ={
        build.onResolve({ filter: '', namespace: '' }args ={ ...});
        build.onLoad({ filter: '', namespace: ''}args ={ ... });
        build.onStart(() ={ ... });
        build.onEnd((result) ={ ... });
    }
}
複製代碼

其中,setup 可以幫助我們在 build 的各個過程中註冊 hook

Esbuild 對外提供的 hook 比較簡單,總共 4 個:

正是有了 onResolveonLoadonStartonEnd,我們可以在 build 過程中的解析 url、加載模塊內容、構建開始、構建結束階段介入,做自定義操作。

Esbuild 在 Vite 中的巧妙使用

瞭解了 Esbuild 的基本用法以後,小編就帶大家一起來看看 Vite 是怎麼利用 Esbuild 來做預構建和內容轉換的。

預構建

先來回顧一下爲什麼要做預構建。

原因有兩點:

要完成預構建,最關鍵的兩點是找到項目中所有的第三份依賴和對第三方依賴做合併、轉換。藉助 EsbuildVite 很輕鬆的實現了這兩個訴求。

  1. 定義一個帶 onResolve hookonLoad hookesbuild plugin

  2. 執行 esbuildbuild 方法做打包構建;

這樣,通過兩次 esbuild.build,預構建就完成了。

middlewares 中內容轉換

Vite 中源文件的轉換是在 dev server 啓動以後通過 middlewares 實現的。

當瀏覽器發起請求以後,dev sever 會通過相應的 middlewares 對請求做處理,然後將處理以後的內容返回給瀏覽器。

middlewares 對源文件的處理,分爲 resolveloadtransformparser 四個過程:

  1. resolve - 解析 url,找到源文件的絕對路徑;

  2. load - 加載源文件。如果是第三方依賴,直接將預構建內容返回給瀏覽器;如果是業務代碼,繼續 transformparser

  3. transfrom - 對源文件內容做轉換,即 ts -> js, less -> css 等。轉換完成的內容可以直接返回給瀏覽器了。

  4. parser - 對轉換以後的內容做分析,找到依賴模塊,對依賴模塊做預轉換 - pre transform 操作,即重複 1 - 4

    pre transformVite 做的一個優化點。預轉換的內容會先做緩存,等瀏覽器發起請求以後,如果已經完成轉換,直接將緩存的內容返回給瀏覽器。

Vite 在處理步驟 3 時,是通過 esbuild.transform 實現的,對比 Webpack 使用各個 loader 處理源文件,那是非常簡單、快捷的。

結束語

有一說一,Vite 通過 Esbuild 來優化預構建和內容轉換的思路非常棒,這給我們以後處理同類問題提供瞭解決方案,真心給尤大點 👍🏻。

另外除了使用 EsbuildVite 內部還有很多可以拿出來單獨講的優化技巧,這個以後有機會小編可以再給大家詳細講講。

最後說一句,如果本文對大家有幫助,那就給小編點個 👍🏻 吧。大家的支持,是小編前進的動力,😄。

關於本文

作者:0o 華仔 o0

https://juejin.cn/post/7129802255120728100

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