Skip to content

🚀 Farm v1.0 is released!

Choose a tag to compare

@wre232114 wre232114 released this 15 Apr 10:46
e715408

Farm⭐️ is a next-generation web build tool written in Rust. It is currently the most powerful, fastest, and most stable Rust web build tool. Since Farm open its source code of version 0.3 in March 2023, after a year of development and contributions by many community developers, version v1.0 has finally been released! The v1.0 version supports a large number of features including lazy compilation, persistent caching, Rust/Js plugins, partial bundling and other capabilities. It is also compatible with the Vite plugin ecosystem. On the basis of perfectly solving the drawbacks of existing tools such as Vite, Farm has both extreme performance and compatibility, it is the real next generation web build tool!

Farm is currently in production and available, and many enterprise projects have been migrated to Farm, and works greatly!

As shown below, in benchmark test of 1000 react components, Farm is 20 times faster than webpack and 10 times faster than Vite. Compared with other tools, it has overwhelming performance advantages in terms of cold start, hot start, HMR, etc. Farm supports and enables a series of performance optimization methods by default, such as lazy compilation, persistent cache/incremental build, multi-threaded parallel compilation, etc.. The larger the project, the more the source files, and the greater the performance advantage.

image

Tested Based on Linux Mint 21 / i5 / 16GB by averaging three times. For details, please refer to benchmark warehouse

1. Features

  • Extremely fast: The core compilation capabilities are implemented using pure Rust, maximum parallel compilation, starting the project in seconds, performing HMR in milliseconds!
  • 🚀 Incremental build: Module-level disk persistent cache supported, unchanged modules won't be compiled twice, hot start time is reduced by 80%, with lazy compilation enabled, preview projects of any size in 1s
  • ⚙️ Massive features: Builtin support for Html, Css/Css modules, js/jsx/ts/tsx, static resources and so on.
  • 🧰 Pluggable & Vite compatible: Fully pluggable, supports both Rust and Js plugins, compatible with the Vite plugin ecosystem.
  • ⏱️ Lazy compilation: non-first-screen pages are compiled on demand and will only be compiled when specific pages are accessed, greatly speeding up the startup of large projects
  • ✔️ Production Optimization: Supports complete production capabilities such as tree shake, compression, syntax downgrade, polyfill, etc., and supports downgrading to ES5
  • 📦 Partial bundling: Bundle thousands of modules into about 20-30 output files according to dependency ship. Perfectly avoiding the two extreme modes of bundle and bundless and can ensure loading performance while improving cache reuse rate.
  • 🔒 Consistency: Development and production use exactly the same strategy, what you see in development is what you get in production
  • 🌳 Compatibility: Compatible with both modern browsers and old browsers (ES5)

Farm v1.0 supports common frameworks such as React, Vue, Solid, Svelte, etc. The project examples section below introduces the use of Farm to build real projects and shows the performance benefits after migration:

2. Quick Start

Farm provides official templates to quickly create a React, Vue, Solid, Svelte, etc. project:

pnpm create farm

Then select the type of project, features, etc. to be created. After the project is created, start the project:

pnpm start

As shown in the picture below, you can create and start your first Farm project in 20 seconds!

v2-ac3f8087e6aa727a6344596533c1008f_b

For more details, please refer to Official Document

3. Compilation features

3.1 Basic compilation capabilities

Farm has built-in compilation capabilities for common modules such as TS/TSX/JS/JSX, CSS/CSS Modules, HTML, static resources, etc., and can be used out of the box without any configuration. For a web app project, you can directly use html as the entry point and import JS/TS and css files. A simplest React project example is as follows, except that @farmfe/plugin-react needs to be installed to support React In addition to Jsx syntax transformation and react refresh injection, other capabilities can be used out of the box.

<!-- index.html -->
<html>
     <head>...</head>
     <body>
         <div id="root"></div>
         <script src="./src/index.tsx"></script>
     </body>
</html>

./src/index.tsx is imported in the above html:

// src/index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Main } from './main';

import './index.css';

const container = document.querySelector('#root');
const root = createRoot(container);

root.render(<Main />);

Import the css file through import './index.css';:

/* src/index.css */
#root {
   color: red;
}

Out-of-the-box compilation support is provided for css modules and static resources such as png/svg/font:

// src/main.tsx
//Import images via url by default
import logo from './assets/logo.png';
//Introduce css modules
import styles from './main.module.css';

export function Main() {
     return <img src={logo} class={styles.logo} />;
}

These basic compilation capabilities are implemented in pure Rust, no additional plugins are needed. For files of html, ts/tsx, css/css modules, png/svg/font and other static resources, they can be compiled and bundled out of the box. Farm treats various types of modules html, css, js/ts/tsx, etc. as first-class citizens, and bundle various types of modules into several deployable products, using the same bundling rules.

3.2 Lazy compilation

For any dynamically imported modules (including js/ts, css, etc.), compilation will be delayed and will only be compiled when the resources actually need to be loaded. This will greatly improve the startup performance of large projects! For example, for large projects, there are often multiple dynamically loaded routes:

// Define routes and import them dynamically
export const routes = [
   {
     path: '/',
     component: () => import('./pages/home.vue')
   },
   {
     path: '/about',
     component: () => import('./pages/about.vue')
   },
   // ...
];

When lazy compilation is enabled, import('./pages/home.vue') will only be compiled when the /home route is accessed. Other routes such as /about will also not be compiled before being accessed. Neither /pages/about.vue nor its dependencies will be compiled. Through reasonable use of lazy compilation + persistent cache, the startup time of each route in large projects can be compressed to less than 1s, greatly improving the development performance of large project!

2c8d08f5b1fd42bba94117c8ae3c008f~tplv-k3u1fbpfcp-jj-mark_0_0_0_0_q75 (3)

Lazy Compilation can be configured through compilation.lazyCompilation and it is enabled for start by default.

import { defineConfig } from '@farmfe/core';

export default defineConfig({
     compilation: {
         // Configure to turn off lazy compilation
         lazyCompilation: false
     }
});

3.3 Incremental Building

Farm supports caching module level compiled products to the local disk to support incremental building. Any module won't be compiled twice before it is changed! Incremental building can reduce project startup time by about 80%. For React + Arco Pro Admin Projects, the performance comparison between code start and hot start is as follows:

| |Cold start (without cache) | Hot start (with cache) | Performance gap |
| -------------------- | --------------- | ----- | ------ ----- |
| start | 1519ms | 371ms | Hot start reduction 75% |
| build | 3582ms | 562ms | Hot build reduction 84%

Incremental Building can be configured through compiltion.persistentCache and it is enabled by default.

import { defineConfig } from '@farmfe/core';

export default defineConfig({
     compilation: {
         // Configure to turn off incremental building
         persistentCache: false
     }
});

When incremental building is enabled, Farm will cache all compilation actions that affect performance to node_modules/.farm directory at module granularity, for example, resolve/load/transform/parse AST, compression, code generation and so on, during the next compilation, the cache will be read from the .farm directory, eliminating a large number of repeated calculations to greatly improve the compilation performance.

For more details, refer to the document Incremental Build

3.4 Production Optimization/Browser Compatibility

Farm fully supports production builds. Many enterprise projects have already used or migrated to Farm, and the results are quite good!

For production builds, Farm has the following optimizations enabled by default:

  • Tree Shake: For the ESM module, all unused export and other statements will be deleted to reduce the product size
  • Compression: The product (Html/JS/CSS) will be mangled and compressed to reduce the product size
  • Syntax downgrade and Polyfill: By default, farm targets browser that supports the ES2017 specification, and automatically downgrade syntax that is not supported by ES2017, and automatically inject Polyfill for unsupported APIs.

Farm supports downgrading products to ES5. If your project has strong compatibility requirements, you can configure it through targetEnv: 'browser-legacy':

import { defineConfig } from '@farmfe/core';

export default defineConfig({
     compilation: {
         output: {
             targetEnv: 'browser-legacy'
         }
     }
})

For more details, please refer to the document Build For Production

3.5 Partial Bundling

Partial Bundling is the strategy used by Farm to bundle modules. The goal of partial bundling is to find a balance between bundle and bundless, by bundling related modules to improve loading performance, while not losing cache granularity as much as possible

Currently, there are two main ways for build tools (such as webpack, rollup) to handle modules: Full bundling or native ESM. But they all have disadvantages:

  • For full bundling, the bundler is designed to bundle everything together and then split it out for optimization, but code splitting is often difficult to configure and manually balancing resource loading performance and cache hit rate is difficult.
  • For native ESM, each module can be compiled and cached separately, but when the project scale becomes large and there are hundreds or thousands of module requests, the loading performance will be seriously affected.

image

The above figure represents the two extremes of bundle and bundless: bundle method bundles all TS/JS/TSX and CSS into an output file, and the cache reuse rate is low, and bundle splitting configuration is complex and difficult; bundless does not bundle at all. For large projects, there are often hundreds or thousands of source modules. Each time the page refreshes is accompanied by a large number of module requests, which seriously affects performance and development experience.

So I've been wondering if there is a strategy to avoid these two extreme cases - maybe we could do partial bundling? We can directly bundle the project into a number of limited quantity and balanced size resources. I named this kind of thinking Partial Bundling - Find a balance between Full Bundling and No Bundling, by partial bundling related modules to improve loading performance, while not losing cache granularity as much as possible.

image

As shown in the figure above, Farm uses partial bundling to bundle thousands of modules with dependencies into limited js and css products, eliminating dependencies while limiting the number of requests. Found a balance between bundle and bundless.

Based on the idea of ​​Partial bundling, Farm designed a complete set of bundling algorithms and provided an full implementation. Unlike other build tools, Farm does not try to bundle everything together and then split the bundle using optimization strategies like splitChunks. Instead, Farm bundles the project directly into multiple product files. For example, if hundreds of modules are needed to launch and render an html page, Farm will try to bundle them directly into 20 to 30 output files based on the partial bundling algorithm.

The goals of Farm Partial Bundling are:

  1. Reduce the number of requests and request hierarchy: Reduce hundreds or thousands of module requests to 20-30 requests, avoid a large number of concurrent requests, and avoid loading modules layer by layer in topological order due to the dependency hierarchy, thus speed up the loading of resources.
  2. Improve cache hit rate: Related modules will be bundled together as much as possible. When some modules are changed, it is ensured that only a few output files are affected, so the cache hit rate can be improved for the project.

For traditional bundler, it may be difficult for us to achieve the above goals through complex splitChunks or manualChunks configuration, but Farm supports it natively through partial bundling.

For more details on partial bundling, refer to the document Partial Bundling.

3.6 Plugin Ecosystem

Farm is completely pluggable, and has designed a complete plugin system for community plugins. Currently Farm supports the following 4 types of plugins:

  • Farm compilation plugin: Supports Rust plugin and Js plugin, using rollup style hooks
    • Farm Rust Plugin: Plugin written in Rust, which has the best performance
    • Farm Js plugin: Plugin written in JS, the performance is worse than Rust, but it is more convenient to write
  • Farm runtime plugin: Extend Farm’s runtime module system
  • Vite/Rollup/Unplugin: Farm supports the Vite/Rollup/Unplugin plugin out of the box
  • Swc plugin: Farm supports the Swc plugins out of the box

An overview of Farm plugin hooks is as follows:

image

Vite/Rollup/Unplugin plugin compatibility is implemented through the adapter based on the above hooks

Farm provides a large number of official plugins to support common compilation capabilities, such as:

  • @farmfe/plugin-react: supports React Jsx conversion and React Refresh
  • @farmfe/js-plugin-sass: supports Sass compilation
  • @farmfe/js-plugin-less: supports Less compilation
  • @farmfe/js-plugin-postcss: supports Postcss compilation
    *...

Most of the Vite/Rollup/Unplugin plugins are available out of the box in Farm:

  • @vitejs/plugin-vue: supports Vue compilation
  • @vitejs/plugin-vue-jsx: supports Vue Jsx compilation
  • unplugin-auto-import
  • unplugin-auto-component
    *...

For information on using various plugins in Farm, please refer to Using Plugins. For an introduction to official/community plugins, please refer to [Plugins](https://www. farmfe.org/docs/plugins/official-plugins/overview)

Writing your own Farm plugin is also quite simple. Farm provides plugin templates for one-click creation:

pnpm create farm-plugin

Supports both Rust plugins and JS plugins, please refer to the document Writing Plugins for details.

3.7 SSR support

Farm supports SSR (Server-Side Rendering). SSR can greatly improve the loading performance of the first screen, improve the SEO of the page, etc. Based on Farm, you can achieve extremely fast SSR building experience!

A typical Farm SSR project structure is as follows:

.
├── index.html
├── farm.config.ts
├── farm.config.server.ts
├── server.js
└── src
     ├── index-client.tsx
     ├── index-server.tsx
     └── main.tsx

You need to provide the client and server entries respectively, and then use Farm to build the client and server entries. Farm provides SSR examples for common frameworks:

For more details about SSR, refer to the document Server-Side Rendering

4. Real World Project Examples

Farm supports common frameworks such as React, Vue, Solid, Svelte, etc., and real projects have been migrated from Webpack/Vite to Farm. Below we provide examples of admin projects for the two most commonly used frameworks (React, Vue).

4.1 React Admin Project

2f4dbfc2068b403787e7cb18c62e777c~tplv-k3u1fbpfcp-jj-mark_0_0_0_0_q75 (1)

As shown in the picture above, Farm can hot-start and render a complex admin project in 500ms.

4.2 Vue Admin Project

In the picture below(Farm is at the bottom and Vite is at the top). It can be clearly seen that under the same conditions of compiling the Vue project with hot start + full Vite plugin, Farm is 5 times faster than Vite. This project is migrated from Vite to Farm. Since Farm is compatible with the Vite ecosystem, all Vite plugins of the project can be directly reused, the migration is really simple.

88652ef06e5d4738be281f8d39a4bbf4-tplv-k3u1fbpfcp-jj-mark_3024_0_0_0_q75 (2)-1713177820660

5. Summary

Farm is developed and built by the open source community. After nearly two years of development, version 1.0 has finally been released. Version 1.0 includes all the capabilities needed for web build tools. Through Rust multi-threading + lazy compilation + incremental compilation, etc., it greatly improves web project build performance and provides a more extreme building performance experience!

In the future Farm will:

  1. Continue to build more top-level frameworks, such as SSR framework.
  2. Extend the Rust plugin ecosystem, use Rust to implement or reconstruct existing common tools, and provide a more extreme performance experience

Acknowledgments:

  • brightwu(吴明亮): Farm author and Lead Maintainer, created, designed and implemented most of the functions of Farm
  • ErKeLost: Farm core maintainer, designed and implemented most of the Node side and Rust Resolver capabilities
  • shulandmimi: Farm core maintainer, developed and maintained a large number of Farm plugins, implemented and optimized a large number of Rust Compiler's builtin capabilities, such as compression, Tree Shake, etc.
  • Farm organization members: Participated in the optimization and development of various features and bugfixes of Farm, etc.
  • Community Contributors: Participated in Farm contributions and assisted in the implementation of various features and bugfixes