前端新利器——Rspack

前言

前端界总是如火如荼,朝气蓬勃,这不,还没有把所有的项目更新到Webpack@5,Turbopack还没站起来,Rspack又来了,我们来看看这个东西有多厉害。

Rspack是什么?

Rspack是由字节跳动开源的前端构建工具,是一个基于 Rust 的高性能构建引擎, 具备与 Webpack 生态系统的互操作性,可以被 Webpack 项目低成本集成,并提供更好的构建性能。

Rspack 已经实现了 Webpack 大部分的主要功能,目前的功能已经能够满足大多数项目的需求。同时,已经在其内部的几百个业务上完成了落地,取得了 5 ~ 10 倍编译性能的提升。

和其他构建工具的区别

和 Webpack 的区别

Webpack 是目前最为成熟的构建工具,有着活跃的生态,灵活的配置和丰富的功能,但是其最为人诟病的是其性能问题。Rspack 解决的问题核心就是 Webpack 的性能问题。 Rspack 比 Webpack 快得益于如下几方面:

  • Rust 语言优势: Rspack 使用 Rust 语言编写, 得益于 Rust 的高性能编译器支持, Rust 编译生成的 Native Code 通常比 JavaScript 性能更为高效。

  • 高度并行的架构: Webpack 受限于 JavaScript 对多线程的羸弱支持,导致其很难进行高度的并行化计算,而得益于 Rust 语言的并行化的良好支持, Rspack 采用了高度并行化的架构,如模块图生成,代码生成等阶段,都是采用多线程并行执行,这使得其编译性能随着 CPU 核心数的增长而增长,充分挖掘 CPU 的多核优势。

  • 增量编译: 尽管 Rspack 的全量编译足够高效,但是当项目庞大时,全量的编译仍然难以满足 HMR 的性能要求,因此在 HMR 阶段,我们采用的是更为高效的增量编译策略,从而保证,无论你的项目多大,其 HMR 的开销总是控制在合理范围内。

  • 内置大部分的功能: 事实上 Webpack 本身的性能足够高效,但是因为Webpack 本身内置了较少的功能,这使得我们在使用 Webpack 做现代 Web App 开发时,通常需要配合很多的 plugin 和 loader 进行使用,而这些 loader 和 plugin 往往是性能的瓶颈,而 Rspack 虽然支持 loader 和 plugin,但是保证绝大部分常用功能都内置在 Rspack 内,从而减小 JS plugin | loader 导致的低性能和通信开销问题。

和 Vite 的区别

Vite 在生产构建中依赖了 Rollup ,因此与其他基于 JavaScript 的工具链一样,面临着生产环境的构建性能问题。

另外,Rollup 相较于 Webpack 做了一些平衡取舍。比如,Rollup 缺失了 Webpack 对于拆包的灵活性,即缺失了 optimization.splitChunks 提供的很多功能。

和 Turbopack 的区别

Rspack 和 Turbopack 都是基于 Rust 实现的 bundler,且都发挥了 Rust 语言的优势。

与 Turbopack 不同的是,Rspack 选择了对 Webpack 生态兼容的路线,一方面,这些兼容可能会带来一定的性能开销,但在实际的业务落地中,我们发现对于大部分的应用来说,这些性能开销是可以接受的,另一方面,这些兼容也使得 Rspack 可以更好地与上层的框架和生态进行集成,能够实现业务的渐进式迁移。

和Esbuild的区别

Esbuild的问题:

  • 缺乏对 JavaScript HMR 和增量编译的良好支持,这导致大型项目中的 HMR 性能较差。
  • 拆包策略也非常原始,难以满足业务复杂多变的拆包优化需求。

和Rollup的区别

Rspack 和 Rollup 两者的侧重领域不同,Rollup 更适合用于打包库,而 Rspack 适合用于打包应用。因此 Rspack 对打包应用进行了很多优化,如 HMR、Bundle splitting 等功能,而 Rollup 则比 Rspack 的编译产物对库更为友好,如更好的 ESM 产物支持。 社区上也有很多的工具在 rollup 基础上进行了一定的封装,提供了对应用打包更友好的支持,如 vite 和 wmr, 目前 Rspack 比 rollup 有更好的生产环境构建性能。

框架支持

Rspack目前支持的框架有:

  • React

    Rspack 提供两种方案来支持 React:

    • 使用 Rsbuild:Rsbuild 提供对 React 开箱即用的支持,能够快速创建一个 React 项目,详见 “Rsbuild - React”。
    • 手动配置:你可以参考文档,手动添加 React 相关的配置。
  • Vue

    Rspack 提供两种方案来支持 Vue:

    • 使用 Rsbuild:Rsbuild 提供对 Vue 3 和 Vue 2 开箱即用的支持,能够快速创建一个 Vue 项目,详见 “Rsbuild - Vue 3” 或 “Rsbuild - Vue 2”。
    • 手动配置:你可以参考文档,手动添加 Vue 相关的配置。
  • SolidJS

    Rspack 提供两种方案来支持 Solid:

    • 使用 Rsbuild:Rsbuild 提供对 Solid 开箱即用的支持,能够快速创建一个 Solid 项目,详见 “Rsbuild - Solid”。
    • 手动配置:你可以参考文档,手动添加 Solid 相关的配置。
  • Svelte

    Rspack 提供两种方案来支持 Svelte:

    • 使用 Rsbuild:Rsbuild 提供对 Svelte 开箱即用的支持,能够快速创建一个 Svelte 项目,详见 “Rsbuild - Svelte”。
    • 手动配置:你可以参考文档,手动添加 Svelte 相关的配置。
  • NestJS

    Rspack 不仅能用于构建前端应用,也可以用于构建 Node.js 应用,你可以使用 Rspack 来构建 NestJS,Rspack 提供了一个 NestJS Example 的例子供参考。

从Webpack迁移

虽然 Rspack 尽可能地兼容了 webpack 的常用 API,但是不可避免地存在一些不同,或是相同的功能在 Rspack 中有更高性能的实现方式。

修改配置

可以参考「Webpack 配置兼容性」进行配置迁移。

处理Loader

使用 builtin:swc-loader 替代 babel-loader

Rspack 使用 builtin:swc-loader 对 TypeScript、JSX 以及最新的 JavaScript 语法进行转换,这意味着如果你的 babel-loader 只是为了支持 TypeScript、JSX 以及更新的 JavaScript 语法,那么完全可以使用 builtin:swc-loader 替代 babel-loader。

如果你的 babel-loader 是为了支持自定义的转换逻辑,那么这部分的 babel-loader 可以保留,但是我们不鼓励用户对大量的文件使用 babel-loader,因为这会导致严重的性能恶化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
module.exports = {
   module: {
     rules: [
-      {
-        test: /\.tsx?$/i,
-        use: [
-          {
-            loader: 'babel-loader',
-            options: {
-              presets: ['@babel/preset-typescript'],
-            },
-          },
-        ],
-        test: /\.jsx?$/i,
-        use: [
-          {
-            loader: 'babel-loader',
-            options: {
-              presets: ['@babel/preset-react'],
-            },
-          },
-        ],
-      },
+      {
+        test: /\.(j|t)s$/,
+        exclude: [/[\/]node_modules[\/]/],
+        loader: 'builtin:swc-loader',
+        options: {
+          sourceMap: true,
+          jsc: {
+            parser: {
+              syntax: 'typescript',
+            },
+            externalHelpers: true,
+            transform: {
+              react: {
+                runtime: 'automatic',
+                development: !prod,
+                refresh: !prod,
+              },
+            },
+          },
+          env: {
+            targets: 'Chrome >= 48',
+          },
+        },
+      },
+      {
+        test: /\.(j|t)sx$/,
+        loader: 'builtin:swc-loader',
+        exclude: [/[\/]node_modules[\/]/],
+        options: {
+          sourceMap: true,
+          jsc: {
+            parser: {
+              syntax: 'typescript',
+              tsx: true,
+            },
+            transform: {
+              react: {
+                runtime: 'automatic',
+                development: !prod,
+                refresh: !prod,
+              },
+            },
+            externalHelpers: true,
+          },
+          env: {
+            targets: 'Chrome >= 48', // browser compatibility
+          },
+        },
+      },
     ],
   },
 };

移除 css-loader 、 style-loader 和 mini-css-extract-plugin

Rspack 内置支持了 css 模块类型 ,原生 css 模块类型内置了对 css、css hmr、css module 以及 css 提取功能的支持,这意味着你不需要再为 css 文件单独配置 css-loader、style-loader 和 mini-css-extract-plugin。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");

 module.exports = {
   module: {
     rules: [
-      {
-        test: /\.css$/i,
-        use: [
-          isDev ? "style-loader" : MiniCssExtractPlugin.loader,
-          "css-loader",
-        ],
-      },
+      {
+        test: /\.css$/i,
+        type: "css", // this is enabled by default for .css, so you don't need to specify it
+      },
     ],
   },
   plugins: [],
 };

使用 Asset Modules 来代替 file-loader、url-loader 和 raw-loader

Rspack 对齐 webpack 5 的 Asset Modules,这意味着你可以使用 Asset Modules 来代替 file-loader 和 url-loader。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module.exports = {
   module: {
     rules: [
+      {
+        test: /\.(png|jpe?g|gif)$/i,
+        type: "asset/resource",
+      },
+      {
+        test: /^BUILD_ID$/,
+        type: "asset/source",
+      },
-      {
-        test: /\.(png|jpe?g|gif)$/i,
-        use: ["file-loader"],
-      },
-      {
-        test: /^BUILD_ID$/,
-        use: ["raw-loader",],
-      },
     ],
   },
 };

从Create React App迁移

请参考 Rsbuild 提供的 Create React App 迁移指南 来了解更多内容。

结语

本篇只是抛砖引玉,将Rspack的印象较深的内容记录下来,总体来说该工具能让我们的应用构建速度大大提高,使工作效率有进一步的提升。

更多详细文档可以参考Rspack