271 - 《手撕源码 29:Farm》

发布于 2023年3月7日

这个系列好久好久没更了。早上看到 Farm 的新闻,没忍住好奇心,把手上的事情放了放,专门花几个小时把源码翻了一遍。在此做下记录。

1、先八卦了下作者,哈哈,因为他在 github 上填的腾讯、知乎上填的还是字节,于是就打听了下。Github id wre232114,之前在字节互娱部门做的基于 Rust 的构建引擎,后来架构变更,被 rspack 合并,再后来离职跳到腾讯,并把这套方案,命名为 Farm,一个基于 Rust + SWC 的构建工具。

2、尝鲜可以 pnpx @farmfe/cli@latest create 新建个项目试试。可以看到,1)从 farm.config.ts 里的 input 可以看出,入口文件是 html 类型(但从实现上看应该不挑),2)挑几个刺,没 tsconfig.json,package.json 里依赖用 *,start 命令应该用 dev 命令,3)试了下加 antd 依赖再用个 Button,就报错了,应该是 revolve 规则的问题,有兴趣的可以直接去提 PR。

3、其他的一些小点。1)协议是 MIT,2)作者应该不用 webstorm,好多无伤大雅的小问题,比如我还顺手混了个 typo 的 PR,3)没有官网文档,哈哈,我还想先去翻翻文档的,那就只能直接翻源码了。

4、整体架构作者有贴一个架构图。1)整体实现分 node 和 rust 两部分,通过 napi 做相互通讯(应该是标配了),2)node 的包在 packages 目录下,主要是 cli 和 core,cli 除了 start、build、create 还有 plugin 的 create 和 build,core 通过 optionalDependencies 声明 binding 库,基于 @napi-rs/cli 打包而来,3)rust 的包在 crates 下,主要是 core、compiler、node 和各个插件包。

5、packages/core 主要 3 个功能,build、start 和 config。1)build 命令就是 await (new Compiler(config)).compile(),其中 Compiler 的实现来自 Rust,2)start 命令的实现里包含了 DevServer(HmrEngine、lazyCompilation) + Compiler + FileWatcher,其中 lazyCompilation 是一个中间件,接收到匹配请求后会执行 await compiler.update(paths) 添加额外需要编译的 paths,3)config 里有个点是,如果是 ts 文件,会先用自己的 compiler 编译一遍,存在临时目录下,再 import() 进来。

6、crates/node 是连接 node 和 rust 的库,会通过 @napi-rs/cli 打包成比如 @farmfe/core-darwin-arm64 这样的库。有一点值得注意的是,Farm 同时支持 js plugin 和 rust plugin,其中 object 类型的是 js plugin,会通过 JsPluginAdapter 转成 rust plugin 给 Compiler 使用。

7、crates/compiler 是 Farm 里最核心的包,实现了大量复杂的逻辑,包括 build、generate、plugin、module graph 等。

8、先说插件体系。Farm 全部由插件实现,和 webpack 比较像,也是我喜欢的方式,哈哈。1)PluginDriver 里通过宏的方式定义了一堆 hooks,完整列表有 build_start、resolve、load、parse、process_module、analyze_deps、finalize_module、build_end、generate_start、optimize_module_graph、analyze_module_graph、partial_bundling、process_resource_pot_map、render_resource_pot、optimize_resource_pot、generate_resources、finalize_resources、generate_end、finish,大纲能猜出意思,然后每个插件实现对应的 hook 就可以了,2)这些 hook 里有些是 async,有些是 serial,有些是 first,等等,满足不同场景的需要,3)目前内置了 7 个插件,runtime、resolve、script、html、css、react 和 partial_bundling。

9、compile 的过程主要分两步,build 和 generate。1)build 负责从入口文件开始生成 module graph,在这个过程里会做 resolve(找到模块)、load(挂载文件)、transform(编译文件)、parse(解析文件产出语法树)、process_module(做一些语法树相关的事)、analyze_deps(分析有哪些依赖,然后让依赖重新走一遍这些流程) 、finalize_module 等事情,2)generate 负责基于 module graph 生成产物。

10、插件 farmfe_plugin_script、farmfe_plugin_css 和 farmfe_plugin_html 顾名思义,分别负责了 JS、CSS 和 HTML 的编译。而他们三个背后都是基于 SWC 做文件的 lexer、parser 和 codegen。1)js 的 parse 基于 swc_ecma_pars

内容预览已结束

此内容需要会员权限。请先登录以查看完整内容。