farm 是一个用 native 方式重写的 vite,拥有极快的构建速度。
yarn pnp 的原理是更改了node的loader,resolve dep方法,将寻找依赖的读取方式从 node_modules 成 zip 中读取,可以解决依赖碎片化和IO读写过深的问题。
从下面的源码可知,farm start 会调用 compiler, compiler 实际是与 native 绑定的。意味着读取文件以及最终的输出都是由 native 处理的,不会经过 nodejs。所以 yarn pnp 模式是不可以跟 farm 结合使用的。除非后续 farm 支持了 yarn pnp 的读取方式。
compiler js 包调用路径源码: https://github.com/farm-fe/farm/blob/main/packages/core/src/compiler/index.ts
compiler native 的源码:https://github.com/farm-fe/farm/blob/main/crates/compiler/src/lib.rs#L128
compiler 具体动作
- build
- build_module_graph_threaded
- resolve_module / build_module # Resolving, loading, transforming and parsing a module, return the module and its dependencies if success
export async function start(
inlineConfig?: FarmCLIOptions & UserConfig
): Promise<void> {
inlineConfig = inlineConfig ?? {};
const logger = inlineConfig.logger ?? new Logger();
setProcessEnv('development');
try {
const resolvedUserConfig = await resolveConfig(
inlineConfig,
'development',
logger
);
if (
resolvedUserConfig.compilation.lazyCompilation &&
typeof resolvedUserConfig.server?.host === 'string'
) {
await setLazyCompilationDefine(resolvedUserConfig);
}
const compiler = await createCompiler(resolvedUserConfig, logger);
const devServer = await createDevServer(
compiler,
resolvedUserConfig,
logger
);
await devServer.listen();
} catch (error) {
logger.error('Failed to start the server', { exit: true, error });
}
}
export async function createCompiler(
resolvedUserConfig: ResolvedUserConfig,
logger: Logger
) {
const {
jsPlugins,
rustPlugins,
compilation: compilationConfig
} = resolvedUserConfig;
const compiler = new Compiler(
{
config: compilationConfig,
jsPlugins,
rustPlugins
},
logger
);
for (const plugin of jsPlugins) {
await plugin.configureCompiler?.(compiler);
}
return compiler;
}
import { Compiler as BindingCompiler } from '../../binding/index.js';
export class Compiler {
private _bindingCompiler: BindingCompiler;
private _updateQueue: UpdateQueueItem[] = [];
private _onUpdateFinishQueue: (() => void | Promise<void>)[] = [];
public compiling = false;
constructor(
public config: Config,
private logger: ILogger = new Logger()
) {
this._bindingCompiler = new BindingCompiler(this.config);
}
async compile() {
if (this.compiling) {
this.logger.error('Already compiling', {
exit: true
});
}
this.compiling = true;
if (process.env.FARM_PROFILE) {
this._bindingCompiler.compileSync();
} else {
await this._bindingCompiler.compile();
}
this.compiling = false;
}
...
}
题外话:长期使用了一段时间(三个月以上),不能跟版本,非常容易掉坑里。不要盲目上该替代品,一些新颖的技术根本没有广泛使用。依赖一旦更新,就可能无法跑起来。好处是构建速度非常快,但是号称的开发环境产物和生产环境产物一致并无实现。如果要查构建的线上问题,将非常耗时。稳定且足够好的技术并不容易被替代。