前端新利器——Rspack

前言

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

Rspack是什么?

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

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

和其他构建工具的区别

Webpack 的区别

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

  • 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 的区别

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

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

Esbuild的区别

Esbuild的问题:

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

Rollup的区别

RspackRollup 两者的侧重领域不同,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