Parcel 在 React 社区里一直以零配置著称,安装后几乎不用写任何构建文件就能启动开发服务器。但当项目规模增长到数百个模块、引入大量图片和样式后,基于 JavaScript 的打包器在依赖扫描、转译和压缩阶段会明显变慢。Farm 由 Rust 编写,把文件读取、AST 解析、依赖收集和代码压缩这些高频操作放到原生层执行,同时通过增量编译和持久缓存降低重复构建成本。迁移到 Farm 并不会改变 React 组件本身的编写方式,真正的改动集中在构建脚本、配置文件和部分环境变量用法上。

为什么 Farm 适合 React 项目
Farm 的核心设计思路是尽量降低开发服务器的启动成本。与 Parcel 相比,Farm 在冷启动时不需要完整遍历所有依赖,而是采用按需编译策略。开发服务器启动后,只有被浏览器请求到的模块才会进入编译队列,这让包含大量路由和组件库的项目能更快看到页面。对于 React 项目来说,组件数量多、文件分散是常态,按需编译能明显减少等待时间。
JSX 和 TypeScript 的支持是 React 项目的首要条件。Farm 官方提供 React 插件,内部使用 SWC 完成 JSX 转换,因此无需额外配置 Babel。同时,Farm 对 CSS Modules、Sass、Less、静态资源导入都有内置处理,减少了过去在 Parcel 中分散的 transformer 配置。你只需要安装对应插件或预处理器,Farm 会自动识别并接入构建流程。
另一个值得关注的点是内存占用。Rust 编译的依赖收集器和缓存系统比 JavaScript 实现更轻量,长时间运行时不容易出现 Node 进程内存膨胀。对于需要在 Docker 容器或 CI 环境中频繁构建的团队,这一优势会转化为更低的资源成本,也让本地开发时开多个终端窗口变得更加轻松。
迁移前需要理清的配置映射
从 Parcel 到 Farm,第一件事是调整 package.json 中的脚本命令。Parcel 的 parcel serve 和 parcel build 需要替换为 farm start 和 farm build。依赖方面可以移除 parcel、parcel-reporter-* 等包,安装 @farmfe/cli、@farmfe/core 以及 React 插件。
{
"scripts": {
"dev": "farm start",
"build": "farm build",
"preview": "farm preview"
},
"devDependencies": {
"@farmfe/cli": "^1.0.0",
"@farmfe/core": "^1.0.0",
"@farmfe/plugin-react": "^1.0.0",
"typescript": "^5.0.0"
}
}
然后在项目根目录创建 farm.config.ts。如果你在 Parcel 中通过 alias 字段或 tsconfig paths 映射了 @ 指向 src 目录,那么 Farm 的 resolve.alias 可以沿用相同规则。入口文件通常不是 src/index.tsx,而是包含脚本引用的 index.html,这一点和 Vite 类似,与 Parcel 以 HTML 为入口一致。
import { defineConfig } from '@farmfe/core';
export default defineConfig({
plugins: ['@farmfe/plugin-react'],
compilation: {
input: {
index: './index.html',
},
output: {
path: 'dist',
publicPath: '/',
},
resolve: {
alias: {
'@': './src',
},
},
},
server: {
port: 3000,
},
});
这里需要特别注意路径写法。Farm 的 alias 值相对项目根目录,不需要写绝对路径。代理配置也放在 server.proxy 下,与 Parcel 的 proxy 字段非常接近。迁移时可以直接把原有代理规则搬过来,只调整字段位置即可。
环境变量与 API 替换
Parcel 项目里常见 process.env.REACT_APP_API_URL 这类写法,迁移后建议改用 import.meta.env.VITE_API_URL。Farm 默认加载 .env 文件,只暴露以 VITE_ 开头的变量给客户端代码。这样既避免把敏感配置打进产物,也能统一 Vite/Farm 生态的写法。修改业务代码时,全局搜索 REACT_APP_ 前缀并替换为 VITE_ 通常就能完成大部分工作。
如果暂时不想改动业务代码,也可以在 Farm 的 compilation.define 中手动注入 process.env 相关值。define 会在构建时做静态替换,因此只适合字符串或布尔值,不能包含运行时函数。
export default defineConfig({
compilation: {
define: {
'process.env.REACT_APP_API_URL': JSON.stringify('https://api.ipipp.com'),
},
},
});
需要说明的是,直接替换 process.env 并不是 Farm 推荐的长久方案。更稳妥的做法是利用 import.meta.env,配合 TypeScript 的 env.d.ts 声明文件,让编辑器和构建器都能识别自定义环境变量。迁移过程中可以先把环境变量统一改为 VITE_ 前缀,再用 import.meta.env 读取,这样后续切换构建工具也会更省事。
处理样式、图片和 CommonJS 依赖
React 项目中常见的 CSS Modules 在 Farm 中只需要以 .module.css 结尾即可自动启用。Sass 和 Less 则需要安装对应预处理器,Farm 会自动检测并编译。如果之前 Parcel 配置了 PostCSS,例如 autoprefixer,Farm 也支持 PostCSS 插件,可以在 farm.config.ts 中注册。
import { defineConfig } from '@farmfe/core';
import farmPostcssPlugin from '@farmfe/js-plugin-postcss';
export default defineConfig({
plugins: [
'@farmfe/plugin-react',
farmPostcssPlugin({
postcss: {
plugins: [],
},
}),
],
});
静态资源导入沿用 ES module 方式:import logo from './logo.png' 可以直接得到 URL 字符串。小于指定大小的资源会被内联为 base64,较大文件则输出到 dist 目录。这一点与 Parcel 行为相近,但 Farm 的阈值和输出规则可以通过 compilation.assets 调整。
迁移过程中最常见的报错来自 CommonJS 依赖。Farm 对原生 ESM 支持良好,而一些老旧的 React 组件库只发布 CommonJS 版本,可能在依赖扫描或打包阶段抛出模块格式错误。遇到这种情况,可以优先检查依赖是否提供 ESM 入口,升级到较新版本;如果无法升级,再考虑将对应包配置为 external,通过 CDN 或全局变量引入。这个过程与从 Webpack 迁移到 Vite 时的依赖处理思路类似。
实际收益与回退策略
完成迁移后,开发服务器冷启动时间通常能从十几秒降到几秒以内,热更新响应也会更稳定。对于包含数百个组件的后台系统或可视化项目,内存占用下降尤其明显。构建生产包时,Rust 压缩器会并行处理多个 chunk,缩短发布等待时间。这些收益不是靠牺牲功能换来的,因为 JSX、TypeScript、CSS 预处理和静态资源导入这些 React 项目刚需仍然被完整支持。
不过 Farm 的插件生态相比 Parcel 和 Webpack 仍处于扩展阶段。如果项目依赖大量非主流 transformer,迁移前应先检查 Farm 是否有对应插件。建议保留原 Parcel 配置在单独分支,遇到无法解决的兼容问题时可以快速回退。将迁移拆成配置替换、环境变量调整、样式处理验证三个步骤,能让过程更可控,也方便团队成员分阶段验证。
最终你会发现,Farm 并不是要求开发者放弃熟悉的 React 开发方式,而是把构建层从 JavaScript 移到 Rust,让工具本身少占用一些运行资源。对于关注开发效率和 CI 成本的项目,这次迁移通常值得一试。