Giter VIP home page Giter VIP logo

farm's Introduction

Extremely fast Vite-compatible web building tool written in Rust

English | 简体中文

discord chat npm package node compatibility downloads license



Intro

Farm is a extremely fast vite-compatible web-building tool written in Rust. It's designed to be fast, powerful and consistent, aims to provide best experience for web development, which is the real next generation build tool.

Online experience

Edit Farm

Why Farm?

See Why Farm for details.

In short, tools like webpack are too slow, but new tools like Vite are not perfect, Vite has a lot of drawbacks when comes to a large project:

  • A huge number of requests during development:when there are hundreds or thousands modules per page, loading performance severely degraded, it may takes seconds or more when refresh the page.
  • Inconsistency between development and production: Using different strategy and tools in development and production, it's really inconsistent and it's hard to debug online issues.
  • Inflexible Code Splitting: It's hard to control the output of your bundles.

Farm can solve these problems perfectly, and it's really fast cause it's written in Rust. Farm aims to be fast, consistent, flexible, which is the real next generation build tool.

Features

Note

  • Extremely Fast: Written in Rust, start a React / Vue project in milliseconds and perform an HMR update within 20ms for most situations.
  • Incremental Building: Support persistent cache, module level cache enabled by default, any module won't be compiled twice until it's changed!
  • 🧰 Fully Pluggable and Vite Compatible: Everything inside Farm is powered by plugins, Support Vite Plugins out of box. Supports Farm compilation plugins(both Rust and JavaScript plugins, and SWC plugins), Farm runtime plugins and Farm server plugin.
  • ⚙️ Powerful: Compiles JS/TS/JSX/TSX, CSS, Css Modules, HTML, and static assets out of the box. Support official compilation plugins for Popular frameworks/tools like React, Vue, SolidJs, Sass, Less, Postcss and so on.
  • ⏱️ Lazy Compilation: Dynamically imported resources are compiled only when requested, speed up compilation for large scale project. Just write a dynamic import and the imported module won't be compiled when it is executed.
  • 📦 Partial Bundling: Bundle your project into a few reasonable bundles automatically, speeding up resource loading without losing caching granularity. Refer to RFC-003 Partial Bundling for details.
  • 🔒 Consistency: What you see in development will be the same as what you get in production.
  • 🌳 Compatibility: Supports both legacy (ES5) and modern browsers.

Farm has implemented all features of a web build tool, including production optimization like tree shake and minification. It's now 1.0 stable. We have already migrated enterprise projects to Farm, and it works great!

See RFC-001 Architecture for design motivation and architecture.


Getting Started

Create a new Farm(support both React and Vue) project with your favorite package manager:

# with npm
npm create farm@latest
# with yarn
yarn create farm@latest
# with pnpm
pnpm create farm@latest

Visit Farm Documentation to learn more about Farm.

Benchmark

Farm is much faster than similar tool, 20x faster than webpack and 10x faster than Vite in the benchmark:

benchmark

See Benchmark for details.

Contribution

See Contributing Guide.

Chat With Us


Contributors




Contributors of farm-fe/farm New trends of farm-fe
Contributors of farm-fe/farm

Credits

Thanks to:

  • The SWC project created by @kdy1, which powers Farm's code parsing, transformation and minification.

  • The NAPI-RS project created by @Brooooooklyn, which powers Farm's node-binding implementation.

  • The Rollup project created by @lukastaegert, which inspired Farm's plugin system implementation.

  • The Vite project created by Evan You, which inspired Farm's compatibility design of ecosystem.

Author & Maintainer

Author:

Maintainer:

farm's People

Contributors

callqh avatar ccherry07 avatar chovrio avatar chuhoman avatar dependabot[bot] avatar erkelost avatar fairyscript avatar flora025 avatar github-actions[bot] avatar kabutoa avatar liangchaofei avatar maidang1 avatar molvqingtai avatar motea927 avatar naturellee avatar nidmo avatar nirvana-jie avatar oblador avatar rhyzx avatar rss1102 avatar shulandmimi avatar siyou avatar sorrycc avatar ufec avatar wjq990112 avatar wre232114 avatar xguangspbd avatar yoogoc avatar ysy945 avatar zourunfa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

farm's Issues

Support web worker

Web worker usage

new Worker(new URL('./worker.js', import.meta.url));

Problems to resolve:

  • How to deal with dependencies of the worker

fix: deletModule "css" but it will not HMR

  • when I delete a module like this
  • before
import React from "react";
import { Description } from "./comps/description";
import "./main.css";
  • changed
import React from "react";
import { Description } from "./comps/description";
//import "./main.css"; delete this module
  • hope: main.css will be removed.

resolveHook didn't call

  • this is the code of loadHook.

image

  • the next step should be to parse the "App. vue? Lang=css..." file, but the "resolveHook" does not work. The following is the relevant code.
export default function farmVuePlugin(options: object = {}): JsPlugin {
  return {
    name: "farm-vue-plugin",
    resolve: {
      filters: {
        importers: [".vue$"],
        sources: [".*"],
      },
      executor(params, ctx) {
        console.log("resolve:", params.source);
        const { query, filePath } = parsePath(params.source as string);
        query.resolvedPath = params.source as string;
        console.log("beforeQuery:", query);
        return {
          external: false,
          resolvedPath: filePath,
          sideEffects: false,
          query,
          meta: {},
        };
      },
    },
    load: {
      filters: {
        resolvedPaths: [".vue$"],
      },
      executor(params, ctx) {
        const { resolvedPath, query } = params;
        if (query.vue === "true" && query.hash) {
          const styleCode = stylesCodeCache[query.hash];
          return {
            content: typeof styleCode === "string" ? styleCode : "",
            moduleType: query.lang,
          };
        }
        let source = "";
        try {
          source = fs.readFileSync(resolvedPath, "utf-8");
        } catch (err) {
          error({
            id: resolvedPath,
            message: "path is not right,can't readFile",
          });
        }

        const { descriptor } = compiler.parse(source);
        const { source: mainCode, moduleType } = genMainCode(
          descriptor,
          resolvedPath
        );
        return {
          content: mainCode,
          moduleType,
        };
      },
    },
  };
}

implement farm plugin tools

Create plugin CLI tools to support create, build and publish farm plugins automatically, support both rust plugin and js plugin.

We need:

  • Plugin templates for rust plugins and js plugins
  • cli tools for creating, building and publishing rust
  • support cross-compilation for rust plugins

For example:

farm plugin create <my-plugin>

farm plugin build

farm plugin publish

Farm's Roadmap - 2023

Farm aims to provide basic performant compilation support(React tech stack) for web project this year(2022), releasing a stable version which can be used in production.

Project Infrastructure

CI for testing, linting, coverage report, auto release and so on

  • Support node bindings and cross platform tests
  • Cross-platform building and artifact upload
  • Release packages using changesets
  • Gathering rust and ts test coverage and report them as single one

Test spec for rust and ts

  • Shared rust test utilities for the input file/output file diff integration test
  • Shared ts test for input file/executing result diff integration test
  • Utilities for rust plugins test
  • Utilities for js plugins test

Project Management

  • contribution guide
  • issue and pr templates

Farm Core Design

  • Farm Architecture #3
    • Plugin system support both js plugin and rust plugin
      • Well designed plugin hook for the entire compilation flow
      • Js plugins with filtering support
      • rust plugin loading and executing
    • Well designed core data structure like Module, ModuleGroup, ModuleGraph and so on
    • Well designed error handling like rust, give the specific cause and the detailed suggested solution
  • Runtime module system for Browser and Node #9
  • Well designed module merging algorithm, with lock for consistency support
  • Well designed universal cache system
  • Well designed HMR interface
  • Well designed core data structure support all web assets as first class citizen
  • Well designed tree shaking algorithm

Features

Script(js, ts, jsx, tsx) compilation

  • Resolving, parsing, minimizing, code generation and dependencies analyzing for all four script types, jsx/tsx support react by default
  • Strip type for ts/tsx (without type checking)
  • Polyfill, syntax downgrade and api inject
  • Tree-shaking
  • Sourcemap
  • Native support swc plugins

Css(sass, less, css) compilation

  • Resolving, parsing, minimizing, code generation and dependencies analyzing for all three css types
  • Css modules support
  • Sourcemap
  • Native HMR support for link tag and style tag

Html compilation

  • Native support resolving, parsing, minimizing, code generation and dependencies analyzing(script, link tag) for html
  • Prefetch and preload

React compilation

  • React refresh

SSR

  • Executable ESM production for node.js
  • Native react ssr support

Optimization

  • Lazy compilation
  • Module merging
    • Internal well designed module merging algorithm
    • Custom module merging strategy by config

Ecosystem

  • Official React project templates and CLI tools
  • Official website and documents

[Feature] css modules

Support css modules. Seems like swc_css has already support css modules. We should take a investigation on it

Comparison with Turbopack

Turbopack is a build tool created by Vercel. It's also written in Rust. How does farm compare with Turbopack?

[Infra] Test coverage to 90%

Rust Compiler - unit tests and integrated tests

Tests to be done:
[ ] HMR update: test the output result when a module change.
[ ] Css parse and codegen
[ ] static assets parse and codegen

Js - e2e tests

[ ] test react/vue examples in headless browser, make sure the output resources of Farm executable

[Infra] Add testing helpers for Rust compiler

We want to test Rust compiler, make sure it work as expected. see https://github.com/farm-fe/farm/blob/main/crates/compiler/tests/update.rs

we need helpers functions to help us the compiler, for example:

  1. create a rust compiler
#[test]
fn test() {
  let compiler = create_compiler(); // create_compiler is a helper
}
  1. verify the output of the compiler
#[test]
fn test() {
  let compiler = create_compiler();
  compiler.compile();
  expect(compiler, 'output code...'); // expect is a helper
}

change styleTemplate - 'farmId'

  • Paths with the same "css" filename but different "query" parameters are imported, and only the last css file can be applied to the page. This is mainly because "farmId" only depends on the filename and not the query parameter. change dependency of farmId.
  • import code

image

  • package code

image

[RFC-0002] Farm's Runtime Module System

Farm's Runtime Module System

Abstract

As discussed in #3, Farm will design its own runtime module system to simulate ESM and CommonJS in web browsers, this RFC describes how this module system works.

Support for other module systems, like UMD, SystemJS or AMD, shall be provided by external plugins, Farm itself will not provide now.

In compile time, Farm transforms ESM or CommonJS modules to Farm's standard module, especially, ESM's export/import statements will be replaced as they are defined in ECMA specification, leave it as is will lead to runtime errors.

In runtime, Farm manages all modules with runtime code, in general, a farm's module has three stages in its whole lifetime, which are register, load and run.

Architecture

Farm's module system is composed with two parts:

  • Compile time transformation
  • Runtime management

Compile time transformation

All modules will be transformed to a CommonJS-like module style:

  • Module import: require('REQUEST')
  • Module export: exports.foo = 1 / module.exports = {} / module.exports = function () {}

ESM modules will be transformed to CommonJS-like module style, import and export statements defined in ECMAScript specification will be mapped to CommonJS-like module syntax:

Note: require here will be replaced with Farm's actual require implementation of runtime module management.

  • ImportDeclaration:
    • import ImportClause FromClause
      • ImportClause:
        • ImportedDefaultBinding:
          • import foo from 'IDENTIFIER' -> const { foo } = require('IDENTIFIER')
        • NameSpaceImport:
          • import * as ns from 'IDENTIFIER' -> const ns = require('IDENTIFIER')
        • NamedImports:
          • import { foo, bar } from 'IDENTIFIER' -> const { foo, bar } = require('IDENTIFIER')
        • ImportedDefaultBinding, NameSpaceImport:
          • import foo, * as ns from 'IDENTIFIER' -> const ns = require('IDENTIFIER'); const foo = ns.default
        • ImportedDefaultBinding, NamedImports:
          • import foo, { foo, bar, baz as z } from 'IDENTIFIER' -> const { default: foo, foo, bar, baz: z } = require('IDENTIFIER')
    • import ModuleSpecifier:
      • import 'IDENTIFIER' -> require('IDENTIFIER')
  • ExportDeclaration:
    • export ExportFromClause FromClause
      • export * from 'IDENTIFIER';
        • for every export identifier ex from 'IDENTIFIER', module.exports[ex] = require('IDENTIFIER')[ex]
      • export * as ns from 'IDENTIFIER'; - > exports.ns = require('IDENTIFIER')
      • export { foo, bar, baz as z} from 'IDENTIFIER'; -> exports.foo = require('IDENTIFIER').foo; exports.bar = require('IDENTIFIER').bar; exports.z = require('IDENTIFIER').baz
    • export NamedExports:
      • export { foo, bar, baz as z }; -> exports.foo = foo; exports.bar = bar; exports.z = baz
    • export VariableStatement:
      • export var baz = 1 -> export.baz = 1
    • export Declaration:
      • HoistableDeclaration:
        • export function foo() {} -> exports.foo = function foo() {}
        • export function foo* () {} -> exports.foo= function foo* () {}
        • export async function foo() {} -> exports.foo= async function foo() {}
        • export async function foo* () {} -> exports.foo= async function foo* () {}
      • ClassDeclaration:
        • export class foo {} -> exports.foo= class foo {}
      • LexicalDeclaration:
        • export let foo = 1 -> exports.foo = 1
        • export let foo, bar, baz = 1 -> exports.foo = undefined; exports.bar = undefined; exports.baz = 1
        • export const bar = 1 -> exports.bar = 1
        • export const foo = 1, bar = 1 -> exports.foo = 1; exports.bar = 1
    • export default HoistableDeclaration:
      • export default function foo() {} -> exports.default= function foo() {}
      • export default function foo* () {} -> exports.default= function foo* () {}
      • export default async function foo() {} -> exports.default= async function foo() {}
      • export default async function foo* () {} -> exports.default= async function foo* () {}
    • export default ClassDeclaration:
      • export default class foo {} -> exports.default= class foo {}
    • export default [lookahead ∉ { function, async [no [LineTerminator](https://tc39.es/ecma262/#prod-LineTerminator) here] function, class }] AssignmentExpression:
      • ConditionalExpression:
        • export default foo ? bar : baz -> exports.default = foo ? bar : baz
      • ArrowFunction:
        • export default () => 1 -> exports.default = () => 1
      • AsyncArrowFunction:
        • export default async () => 1 -> exports.default = async () => 1
      • LeftHandSideExpression = AssignmentExpression:
        • export default a = 1 (where a is a variable declared with var or let) -> exports.default = a = 1
      • LeftHandSideExpression = AssignmentOperator AssignmentExpression:
        • export default a += 1 (where a is a variable declared with var or let, AssignmentExpresssion: one of *= /= %= += -= <<= >>= >>>= &= ^= |= **=) -> exports.default = a += 1
      • LeftHandSideExpression &&= AssignmentExpression:
        • export default a &&= 1 (where a is a variable declared with var or let) -> exports.default = a &&= 1
      • LeftHandSideExpression ||=AssignmentExpression:
        • export default a ||= 1 (where a is a variable declared with var or let) -> exports.default = a ||= 1
      • LeftHandSideExpression ??=AssignmentExpression:
        • export default a ??= 1 (where a is a variable declared with var or let) -> exports.default = a ??= 1

Examples

Runtime management

Todo

Examples

How to start the development environment?

After installing the dependency, I want to try to start react demo in example, but I am not prompted by an error. How can I start it?
i have local rust environment. Do I need to do something?

node 16.18.0

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.