Rspack 工作流程

1,092 阅读2分钟

RsPack 采用 js + rust 来编写,期望在最大化兼容 webpack 配置的基础上对 rust 的高性能兼而有之,其实就目前前列的 vite 与 turbopack 而言,打包编译的速度其实不分伯仲,只有在特别大量的文件打包时才能显现出 rust 的优势,不过 RsPack 作为一次新的尝试,也有很多可以借鉴的,于是便有了这一系列文章。

rspack 源码结构如下:

image.png

图中主要的代码部分为以 js 编写的 packages 文件夹以及以 rust 编写的 crates 文件夹

  1. packages 文件夹主要负责 环境检测、整体流程控制等,以 tabaple 进行流程控制
  2. crates 文件夹主要进行 编译、打包 等大运算量操作

这么看为什么不全部使用 rust 进行编写,而要拆开进行,源码阅读、编写、调试的难度都增大了

image.png

主要在 rspack 与 rspack-cli 中

rspack-cli 作为 rspack-cli 工具的运行入口提供了 RspackCLI 类

构造函数中 使用了

  • colorette 美化输出
  • yargs 构建交互式命令行 (yargs不完全指南)
  • semver 版本号识别(在运行时会检测 nodejs 的版本,需要最少在 14.0.0 以上)

运行时会注册 两个 命令

  • BuildCommand
  • ServerCommand

使用了

  • @discoveryjs/json-ext 加强 JSON

调用 createCompiler 方法

  • 默认 process.env.RSPACK_CONFIG_VALIDATE = "loose"
  • loadConfig
  • buildConfig
  • 调用 rspack 返回 compiler
  • compiler.run

compiler

  • rspackOptionsCheck -> revalidateWithStrategy
  • createCompiler 创建 compiler
  • 如果 option.watch 为 true 则开启 watchOptions 中文件的监控
  • compiler.run

createCompiler

  • getNormalizedRspackOptions
  • applyRspackOptionsBaseDefaults
  • Compiler 创建 compiler
  • NodeEnvironmentPlugin 注册插件
  • 批量注册用户插件
  • applyRspackOptionsDefaults
  • 调用 compiler.hooks.environment.call
  • 调用 compiler.hooks.afterEnvironment.call
  • RspackOptionsApply
  • 调用 compiler.hooks.initialize.call
  • compiler.run

Compiler 类中所有勾子

hooks: {

       done: tapable.AsyncSeriesHook<Stats>;

       afterDone: tapable.SyncHook<Stats>;

       // TODO: CompilationParams

       compilation: tapable.SyncHook<Compilation>;

       // TODO: CompilationParams

       thisCompilation: tapable.SyncHook<[Compilation, CompilationParams]>;

       invalid: tapable.SyncHook<[string | null, number]>;

       compile: tapable.SyncHook<[any]>;

       initialize: tapable.SyncHook<[]>;

       infrastructureLog: tapable.SyncBailHook<[string, string, any[]], true>;

       beforeRun: tapable.AsyncSeriesHook<[Compiler]>;

       run: tapable.AsyncSeriesHook<[Compiler]>;

       emit: tapable.AsyncSeriesHook<[Compilation]>;

       afterEmit: tapable.AsyncSeriesHook<[Compilation]>;

       failed: tapable.SyncHook<[Error]>;

       watchRun: tapable.AsyncSeriesHook<[Compiler]>;

       watchClose: tapable.SyncHook<[]>;

       environment: tapable.SyncHook<[]>;

       afterEnvironment: tapable.SyncHook<[]>;

       afterPlugins: tapable.SyncHook<[Compiler]>;

       afterResolvers: tapable.SyncHook<[Compiler]>;

       make: tapable.AsyncParallelHook<[Compilation]>;

};

run

  • 开始编译计时
  • 标记编译开始 this.running = true
  • 触发 beforeRun
  • 触发 run
  • 调用 build
  • 记录结束时间
  • 触发 done
  • 标记编译结束
  • 调用回掉函数
  • 触发 afterdone

build

  • 引入 unsafe 的 rust 代码,同时将上下文传递给 rust 函数,进行编译操作

以上是 js 侧的主要流程,主要是进行了插件的注册、配置的初始化、编译流的初始化、搭建 devServer 等