当前位置: 首页 > news >正文

Rspack 源码解析 (1) —— 架构总览:从 Node.js 到 Rust 的跨界之旅

写在前面:本系列文章旨在通过阅读 Rspack 源码,学习rust相关使用场景,了解Rust生态中比较优秀的项目是如何管理Rust代码的,也为自己之后学习并应用Rust指明方向,也愿您能有所得。

Rspack源码结构概览

Rspack的源码是一个标准的Monorepo单体仓库-将多个相关项目、模块的源码都放在同一个代码仓库中统一管理,而不是每个项目一个独立仓库),Rspack的源码目录下有:

  • crates:所有Rust子模块(核心、插件、绑定层等等)
  • packages:所有的JS/TS子包(API、CLI等)
  • tests:自测代码
  • examples:相关示例
  • website:相关文档等
  • scripts:相关构建脚本

整个项目的相对核心的目录我们已经列出来了,当然还会有一些相关配置文件没有一一列举,在后面的源码解析的整个流程中,我们会慢慢说明。

宏观架构:三层世界Node + NAPI + Rust

基于我们上面的目录结构,可以看出来Rspack的整个架构分为三层,分别是:Node.js层、Binding层(Node-API)、Rust Core层

Node.js层:用户接口与生态相融

  • 职责

    • 负责与用户交互(配置、插件、Loader、Cli)
    • 保持与Webpack生态的兼容性
    • 提供JS/TS API和命令行工具
  • 代表目录/文件

    • rspack核心 JS SDK,也就是我们安装的@rspack/core
    • rspack-cli命令行工具,处理rspack build命令
    • rspack.config.js用户配置

Binding层:NAPI跨语言桥梁

  • 职责

    • 通过 napi-rs 将 Rust 能力暴露给 Node.js
    • 负责类型转换、内存管理、回调注册
    • 让JS插件、Loader能与Rust编译器协作
  • 代表目录/文件

    • rspack_binding_api胶水层,定义了 Rust 如何暴露给 Node.js。
    • struct jsCompiler 、 #[napi]宏

Rust Core层:高性能编译引擎

  • 职责

    • 实现所有核心编译流程(模块解析、依赖图、代码生成、优化、产物输出)
    • 插件系统、Loader 调度、缓存、HMR、增量构建等
    • 充分利用 Rust 的并发和类型安全
  • 代表目录/文件

    • rspack_core核心编译器,实现了 Compiler, Compilation, Plugin System 等。
    • crates/rspack_plugin_*内置插件
    • crates/rspack_loader_*内置Loader

源码追踪:一次构建的完整旅程

让我们随着代码的执行顺序,看看 Rspack 是如何启动的。

第一站:用户入口 (Node.js)

当你运行rspack时,代码最终会进入@rspack/core的入口。

文件:packages/rspack/src/rspack.ts

// 简化代码exportfunctionrspack(options:RspackOptions,callback?:Callback):Compiler{// 1. 标准化用户配置constcreateCompiler=(userOptions:RspackOptions)=>{constoptions=getNormalizedRspackOptions(userOptions);// 2. 创建 JS 侧的 Compiler 实例constcompiler=newCompiler(options.context,options);// 3. 注册用户配置的插件if(Array.isArray(options.plugins)){for(constpluginofoptions.plugins){plugin.apply(compiler);}}returncompiler;};// ...returncompiler;}

这部分非常容易理解,和 Webpack 几乎一模一样。

第二站:JS Compiler 与 惰性初始化

Rspack 的一个巧妙设计是Lazy Initialization (惰性初始化)。当你new Compiler()时,Rust 核心其实还没启动,直到你真正调用.run().watch()时。

文件:packages/rspack/src/Compiler.ts

exportclassCompiler{// 持有 Rust 实例的引用#instance?:binding.JsCompiler;constructor(context:string,options:RspackOptionsNormalized){this.hooks={...};// 初始化 Tapable 钩子// 注意:构造函数里并没有初始化 Rust 实例}// 私有方法:获取或创建 Rust 实例#getInstance(callback){// 1. 加载 Native 绑定constinstanceBinding=require('@rspack/binding');// 2. 调用 Rust 的构造函数this.#instance=newinstanceBinding.JsCompiler(this.compilerPath,rawOptions,// 传入处理好的配置this.#builtinPlugins,// 传入内置插件this.#registers,// 传入 JS 回调函数的注册表(用于跨语言 Hook)// ... 传入文件系统);}run(callback){// 真正编译时,才初始化 Rust 实例this.#getInstance((err,instance)=>{instance.build(callback);// 调用 Rust 的 build});}}

初学者提示:这里require('@rspack/binding')加载的是一个.node文件(二进制动态链接库),它是由 Rust 编译出来的。

第三站:穿越 NAPI 桥梁 (The Bridge)

现在我们进入了crates/rspack_binding_api。这是连接 JS 和 Rust 的桥梁。

文件:crates/rspack_binding_api/src/lib.rs

Rspack 使用了napi-rs这个库,通过#[napi]宏,可以轻松地把 Rust 结构体变成 JS 类。

// 这里的 #[napi] 宏表示这个结构体会被导出给 JS 使用#[napi(custom_finalize)]structJsCompiler{// 内部持有一个真正的 Rust Compilercompiler:ManuallyDrop<Compiler>,}#[napi]implJsCompiler{// 这个构造函数对应 JS 里的 new instanceBinding.JsCompiler(...)#[napi(constructor)]pubfnnew(env:Env,// NAPI 环境上下文mutoptions:RawOptions,// 从 JS 传来的配置对象// ... 其他参数)->Result<Self>{// 1. 将 JS 的 RawOptions 转换为 Rust 的 CompilerOptionsletcompiler_options:rspack_core::CompilerOptions=options.try_into()?;// 2. 创建真正的核心编译器letrspack=rspack_core::Compiler::new(compiler_options,// ...);// 3. 返回包装后的 JS 对象Ok(Self{compiler:ManuallyDrop::new(Compiler::from(rspack)),// ...})}// 对应 JS 里的 instance.build()#[napi]pubfnbuild(&mutself,reference:Reference<JsCompiler>,f:Function)->Result<()>{// 在 Rust 的异步运行时中执行构建self.run(...)}}

初学者提示

  • struct类似于面向对象里的 class 属性定义。
  • impl类似于 class 的方法定义。
  • #[napi]是“魔法”,自动生成胶水代码,让 JS 能调用这些 Rust 代码。

第四站:核心引擎 (Rust Core)

最后,我们来到了真正干活的地方:crates/rspack_core

文件:crates/rspack_core/src/compiler/mod.rs(核心逻辑)

pubstructCompiler{puboptions:Arc<CompilerOptions>,// 编译配置pubcompilation:Compilation,// 编译状态管理pubplugin_driver:SharedPluginDriver,// 插件驱动器publoader_resolver:Arc<Resolver>,// Loader 解析器// ...}implCompiler{pubfnnew(...)->Self{// 初始化各种核心组件}}

在 Rust 侧,Compiler是一个长期存在的对象(单例模式),它负责创建Compilation。每次构建(Build)都会产生一个新的Compilation,它包含了模块图(Module Graph)和 Chunk 图。

总结

通过第一篇的架构概览,我们理清了 Rspack 的启动流程:

  1. 用户在 CLI 或脚本中调用rspack()
  2. JS 层 (packages/rspack)处理配置,初始化Compiler.ts
  3. Binding 层 (crates/rspack_binding_api)利用 NAPI 接收配置,创建 Rust 实例。
  4. Core 层 (crates/rspack_core)启动,随时准备进行编译。

给 Rust 初学者的建议
在阅读 Rspack 源码时,不必纠结于通过Arc,Mutex,RwLock这种复杂的并发控制细节(虽然它们在 Rspack 中无处不在)。先关注struct数据结构设计impl方法流程,把 Rust 当作带类型的 Python 或 C++ 来看,会更容易上手。

下一篇预告
我们将深入Compilation(编译过程),看看 Rspack 是如何从一个入口文件开始,构建出整个项目的依赖图谱的(Make Phase)。

http://www.jsqmd.com/news/856524/

相关文章:

  • Centos7.9运行nodejs24报错/lib64/libm.so.6: version `GLIBC_2.27‘ not found
  • 2026年英文论文Turnitin检测深度解读:英文毕业论文AI率超标免费4.8元应对完整方案
  • MASA全家桶汉化包终极指南:让Minecraft模组界面说中文的免费解决方案
  • 安卓设备调试效率翻倍:用Magisk模块实现User版ADB永久免授权(无需重刷系统)
  • watchOS 11.1 Beta 1发布:开发者如何应对快速迭代与系统适配
  • 9索引与视图
  • Verilog时序逻辑设计:从D触发器到状态机的实战指南
  • 深入Linux内存管理:从虚拟内存到OOM Killer的完整解析
  • 如何快速提升麻将水平:Akagi智能助手的完整指南
  • 干耳怎么掏耳朵?油耳用什么掏耳朵比较好?适合油耳朵清理的工具
  • DownKyi深度解析:解锁B站视频管理的全新工作流
  • Pro vs Mega vs Business订阅全解析,深度解读并发生成、私有模型与商用授权红线
  • [qemu+kvm]: smmu stage 2 建立流程
  • 如何高效管理Windows右键菜单:ContextMenuManager专业配置指南
  • 大模型选型生死线:Perplexity指标必须在24小时内完成这6项交叉验证,否则准确率偏差超±37%
  • 国产赛车硬刚欧美强队?Gensors DAM 应力应变数据采集系统讲透造车真相
  • 基于智能体的企业级自主决策与业务运营平台解决方案:AI智能管理驾驶舱、智能管理驾驶舱的四大功能定位、总体方案蓝图、总体规划方案
  • 硅光芯片设计避坑指南:行波MZM调制器仿真中速度失配与损耗的权衡实战
  • 2026年4月贵州评价高的出门纱租赁门店推荐,礼服租赁/男士西服定制/秀禾服租/成人礼礼服租赁,出门纱租赁展厅测评 - 品牌推荐师
  • 马氏体钢1700MS激光焊接热-冶金-力学耦合数值模拟方法【附代码】
  • 从‘黑盒’测试到电路设计:互易定理在排查传感器信号异常时的实战应用
  • 贴片机如何提升电子制造行业的生产效率与质量
  • Sora 2原生导入Blender 4.2:3步实现动态提示词驱动骨骼绑定与物理模拟(附实测FBX+USDZ双通道转换参数表)
  • 金融数据宝藏:期货五档Tick与期权高频数据详解
  • 芜湖装修公司推荐哪家
  • 别再只用SE和CBAM了!手把手教你将轻量级ELA注意力模块集成到ResNet/MobileNet中
  • [特殊字符] 告别类名地狱!Tailwind CSS 语义化转换神器来了
  • SystemVerilog中logic数据类型:编译期捕获多驱动错误的核心优势
  • 仅限首批500名开发者:Perplexity图谱查询性能压测报告(含17.3万节点实测TPS基准数据)
  • 【2026 最新】Kali Linux 零基础教程|超详细!下载 + 安装 + 使用全搞定✅