farm start 流程源码以及为什么 farm 不能组合 pnp 使用

2024-11-25

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;
  }


...

}


题外话:长期使用了一段时间(三个月以上),不能跟版本,非常容易掉坑里。不要盲目上该替代品,一些新颖的技术根本没有广泛使用。依赖一旦更新,就可能无法跑起来。好处是构建速度非常快,但是号称的开发环境产物和生产环境产物一致并无实现。如果要查构建的线上问题,将非常耗时。稳定且足够好的技术并不容易被替代。

copyright ©2019-2024 shenzhen
粤ICP备20041170号-1