今天給大家?guī)淼闹黝}是Farm,即一個快速、強大、本地與生產(chǎn)環(huán)境保持一致的 Web 打包器,目標是解決 Vite 面臨的主要問題。話不多說,直接開始!
1.Vite 的不足
隨著 web 項目規(guī)模的擴大,構建性能成為了開發(fā)者面臨的主要問題。對于一個巨大的前端項目而言,使用 webpack 編譯可能需要 10 分鐘甚至更長時間,而熱更新可能需要超過 10s,從而大大降低了前端開發(fā)的效率。
隨著 vite 的出現(xiàn),它在開發(fā)模式下使用原生的 ESM(即非打包模式) ,同時使用 esbuild 預打包依賴項,極大提升了應用開發(fā)服務器啟動和熱更新效率。但是非打包模式(Unbundled)并不完美,對于大型項目來說還是有很大的問題:
- 海量模塊請求:對于一個大型項目,可能需要加載的模塊有上千個,使用原生模塊系統(tǒng)加載上千個模塊會導致瀏覽器卡死甚至崩潰。
- Dev 和 Production 不一致:在大多數(shù)情況下,本地模塊不能直接用于生產(chǎn)環(huán)境。 因此,非打包工具在生產(chǎn)環(huán)境中依然需要打包流程,從而導致 Dev、Production 不一致。當這種不一致導致生產(chǎn)錯誤時,調(diào)試起來非常麻煩、痛苦。 而 vite 選擇在 dev 環(huán)境使用 esbuild,在 production 中使用 rollup,這進一步擴大了不一致性。
- Vite 在 dev 環(huán)境 之所以這么快,是因為 esbuild, esbuild 是用 go 編寫的。 Go 利用了原生平臺的優(yōu)勢,比 Js 快得多。
2.Farm 的出現(xiàn)
鑒于 Vite 的現(xiàn)狀和面臨的問題,F(xiàn)arm 認為,前端開發(fā)者需要一個快速、強大、本地/生產(chǎn)環(huán)境一致的 Web 打包器,從而解決 Vite 面臨的問題。
其實,F(xiàn)arm 不僅僅是一個用 Rust 重寫的普通打包器,它還包括很多強大和進步的設計。在性能方面,Vite 與其他工具的基準測試(使用 Turbopack 的基準測試,1000 個 React 組件)數(shù)據(jù)如下:

不論是在冷啟動,熱更新等方面,F(xiàn)arm 比 Webpack(純 JS 打包)、Vite(本質(zhì)也算 Rust 方案)、Turbopack(Rust 方案)、Rspack(Rust 方案,字節(jié)開源) 等都有顯著的優(yōu)勢。
值得一提的是,F(xiàn)arm 的作者是 brightwu(吳明亮),曾就職于字節(jié)跳動和騰訊。 Farm 開源時間不到一年,在 Github 上已有 500+的 star,是一個值得持續(xù)關注的項目。
3.Farm 的設計理念
- 性能至上:能用 Rust 編寫的模塊都用 Rust,只有少數(shù)不是性能瓶頸的部分沿用 JS
- dev/production 一致性:確保開發(fā)和生產(chǎn)完全一致,即在開發(fā)中看到的與在生產(chǎn)中得到的一樣。
- 部分打包:Farm 的打包目標不是把所有東西都打包在一起,而是限制資源的請求數(shù)量。 Farm 會根據(jù)依賴關系和資源大小,將項目打包成 20-30 個小資源,在不損失緩存粒度的情況下獲得最佳的資源加載性能。
- Web 資產(chǎn)的一等公民支持:Farm 不需要將所有內(nèi)容轉(zhuǎn)換為 JAVAscript,它將任何資源都視為一等公民,如 html、js/jsx/ts/tsx、css/scss、png/svg 等等都是 Farm 支持的基礎模塊,更多資源可以通過插件支持。
- 兼容性:Farm 適用于舊版 (ES5) 和現(xiàn)代瀏覽器。
- Rollup 風格的插件系統(tǒng):易于創(chuàng)建自己的插件,并且易于從 rollup/vite/webpack 遷移插件/項目。
Farm 的目標是成為真正的下一代構建工具,快速、強大、多環(huán)境一致,并為 Web 開發(fā)人員提供最佳的開發(fā)體驗。
4.使用 Farm
Farm 需要 Node 16 及以上版本,如果開發(fā)者使用的是 linux,請確保操作系統(tǒng)版本為 ubuntu 22 及以上(GLIBC >= 2.32)。
4.1 創(chuàng)建 Farm 項目
@farmfe/cli 包提供創(chuàng)建、啟動和構建 Farm 項目或 Farm 插件的能力。使用如下創(chuàng)建命令來初始化一個新的 Farm 項目。
npx @farmfe/cli@latest create
需要注意的是:create 命令目前只支持初始化一個簡單的 React 項目,但是已經(jīng)在逐步增強功能階段。
4.2 開始項目
首先執(zhí)行 install 命令 ,可以選擇喜歡的包管理器,npm 或 yarn 或 pnpm:
cd farm-react && npm install
// npm
cd farm-react && yarn
// yarn
cd farm-react && pnpm install
// pnpm
npm start
// 開始項目
直接通過瀏覽器訪問地址 http://localhost:9000 即可開始。
4.3 配置項目
該項目由項目根目錄下的 farm.config.ts 文件配置,比如下面是 farm.config.ts 的內(nèi)容:
import { defineConfig } from '@farmfe/core/dist/config';
export default defineConfig({
// 與編譯相關的選項
compilation: {
input: {
//可以是相對路徑或絕對路徑
index: './index.html',
},
output: {
path: './build',
publicPath: '/',
},
// ...
},
// 與開發(fā)服務器相關的選項
server: {
port: 9000,
// ...
},
// 附加插件配置
plugins: [],
});
4.4 Farm RoadMap
目前,F(xiàn)arm 已經(jīng)實現(xiàn)了 Web 構建工具的基本功能, 但是要用于生產(chǎn)環(huán)境部署還有很多事情要做。
- Web 資產(chǎn)(html、css、js/jsx/ts/tsx、靜態(tài)資產(chǎn)等)的解析、加載、轉(zhuǎn)換和資源生成。
- 懶編譯
- Dev Server 和 HMR(支持快速響應)
- 部分打包
- Rust 和 Js 插件系統(tǒng)
- Source Map 支持
- Resources Minimize(暫未支持)
- Tree Shake(暫未支持)
- Css modules(暫未支持)
- 類 Sass 的官方插件(暫未支持)
- 持久緩存(暫未支持)
如上列表所示,目前 Farm 很多生產(chǎn)部署功能還依然在開發(fā)中,值得期待!
5.Farm 高級特性
5.1 懶編譯
當涉及到一個大項目時,開發(fā)者可以拆分成小塊并按需加載,這可以通過動態(tài)導入來實現(xiàn)。
const page = React.lazy(() => import('./page'));
// 懶加載
默認情況下,F(xiàn)arm 會延遲編譯這些動態(tài)導入,只有在真正需要模塊時才編譯它們。
5.2 部分打包(Partial Bundling)
回到 webpack,開發(fā)者經(jīng)常使用 splitChunks 來拆分 bundle,試圖優(yōu)化資源加載時間和提高緩存命中率。 但是配置 splitChunks 很復雜,有時達不到想要的效果。
所以 Farm 引入了 Partial Bundling,根據(jù)依賴關系和資源大小自動將應用程序打包到多個資源中。
5.3 Static Assets 靜態(tài)資源
從 v0.4 Farm 開始支持三種資源加載方式: url, inline, raw 。下面是 url 模式:
import rocketUrl from './assets/rocket.svg'; // return the url of this image
export function Main() {
return <img src={rocketUrl} />; // using the url
}
使用 query ?inline 告訴 Farm 想要內(nèi)聯(lián)資產(chǎn),然后資產(chǎn)將轉(zhuǎn)換為 base64,例如:
// importer
import logo from './assets/logo.png?inline';
// logo is a base 64 str
// the image module
export default 'data:image/png,base64,xxxxx==';
例如,使用 ?raw 告訴 Farm 想要讀取資產(chǎn)的原始字符串
// import
import logo from './assets/license.txt?raw';
// return the content string of the assets
// license.txt
export default 'MIT xxxx';
5.4 Script 腳本
Farm 支持開箱即用地編譯 Js/Jsx/Ts/Tsx,默認將 Jsx/Tsx 編譯為 React。
import Button from './Button';
function ButtonGroup(props: ButtonProps) {
return (
<div>
{props.buttons.map((b) => (
<Button>{b}</Button>
))}
</div>
);
}
默認情況下 Farm 使用 swc 來編譯腳本,可以使用 compilation.script 修改配置。
6.本文總結
本文主要和大家介紹Farm,即一個快速、強大、本地與生產(chǎn)環(huán)境保持一致的 Web 打包器,目標是解決 Vite 面臨的主要問題。當然,正如文中所言,F(xiàn)arm的很多能力還在陸續(xù)開發(fā)、增強中,但是它目的非常明確,是一個值得長期關注的方案。
因為篇幅有限,文章并沒有過多展開,如果有興趣,文末的參考資料提供了優(yōu)秀文檔以供學習。最后,歡迎大家點贊、評論、轉(zhuǎn)發(fā)、收藏!
參考資料
https://farm-fe.github.io/docs/why-farm
https://github.com/farm-fe/farm
https://github.com/farm-fe/performance-compare
https://farm-fe.github.io/docs/features/static
https://farm-fe.github.io/docs/features/script