大家好,我是Echa。
好消息,2023年11月24号字节跳动的ByteDance Web Infra 团队自研 Web 构建工具 Rspack v0.4 正式发布。距离上一个版本 Rspack v0.3 (2023年10月12号)发布了Rspress 1.0 静态站点生成器。该团队在非常努力的打造自身的生态圈,历经重重阻挠,不断的打磨、优化、完善、测试等工序,终于面世上线了。
另外,Rspack 在知名的Github 上原来Star 2k,涨到目前的6.2k,广受前端开发者喜爱。
字节跳动企业是一个非常了不起好企业,里面团队人才济济,更是小编非常崇拜的企业之一。字节跳动成立于2012年3月,目前公司的产品和服务已覆盖全球150个国家和地区、75个语种,曾在40多个国家和地区位居应用商店总榜前列。其旗下产品有今日头条、西瓜视频、抖音、头条百科、皮皮虾、懂车帝、悟空问答等,随便一个产品,那是非常响当当,无人不知,无人不晓。
今天小编带着大家详细介绍 Rspack,也是本篇文章主角。
全文大纲
- Rspack 介绍
- 为什么要做Repack?
- Rspack 性能分析
- 什么是 Rsbuild ?
- Rsbuild 性能分析
- Rsbuild 特性
- Rsbuild 生态圈定位
- Rsbuild 手把手教你快速上手
- Rspack 0.4 更新内容
Rspack 介绍
官网地址:https://www.rspack.dev/
Github:https://github.com/web-infra-dev/rspack
Rspack 是一个基于 Rust 的高性能构建引擎, 具备与 Webpack 生态系统的互操作性,可以被 Webpack 项目低成本集成,并提供更好的构建性能。
Rspack 是由 ByteDance Web Infra 团队孵化的基于 Rust 语言开发的 Bundler,拥有高性能、兼容 Webpack 生态、定制性强等多种优点,它解决了我们在业务场景中遇到的非常多的问题,让很多开发者的体验有了质的提升。
特性
优点
- 启动速度极快: 基于 Rust 实现,构建速度极快,带给你极致的开发体验。
- ? 闪电般的 HMR: 内置增量编译机制,HMR 速度极快,完全胜任大型项目的开发。
- 兼容 webpack 生态: 针对 webpack 的架构和生态进行兼容,无需从头搭建生态。
- 内置常见构建能力: 对 TypeScript、JSX、CSS、CSS Modules、Sass 等提供开箱即用的支持。
- ? 默认生产优化: 默认内置多种优化策略,如 Tree Shaking、代码压缩等等。
- 框架无关: 不和任何前端框架绑定,保证足够的灵活性。
缺点
- Loader 支持有限, Plugin 目前主要靠内置,高级点的使用都比较麻烦或者支持有限,内置后配置都比较简单。
- 更适合庞大的项目,这样运行速度、Build 速度都能保持在 webpack 的 5-10 倍,对中小项目提升有限。
- 只支持 nodejs 14 以上的项目迁移。目前rspack V0.4已经改良支持nodejs 16以上了。
为什么要做Repack?
从Rspack官方的描述来看,他们创建此项目并非是强行造轮子。而是当前的技术方案无法满足他们的需求,所以才决定自研 Rspack,为了彻底解决自身内部前端打包问题。
因为时间对于一个程序员来说很宝贵,尤其是一个正在成长中的程序员,节约时间可以研究更重要的技术难题。
字节跳动内部存在非常多的巨型前端应用,它们有着非常复杂的构建配置,十几分钟甚至半小时的构建耗时,ByteDance Web Infra 研发团队尝试了多种方法去优化这些项目的编译速度,但是社区内存在的方案都或多或少存在一些问题,在对这些问题总结后,ByteDance Web Infra 团队理解到工程师对 Bundler 的诉求是:
- 良好的 Dev 启动性能,npm run dev 是开发者每天需要运行很多次的命令,大型项目每次都需要等待 10 分钟,这对于工程师来说是非常痛苦的,所以优化 dev start 的时间是非常重要的。
- 良好的 Build 性能,npm run build 实在 CI CD 环境中经常运行的指令,他决定了应用生产交付的效率,在生产环境中有些应用经常需要 20 ~ 30 分钟的构建时间,如果能缩短这里的耗时对开发链路也会非常有帮助。
- 足够灵活的配置,用户工程的配置灵活多变,并没有做到完全的统一,在之前尝试将 Webpack 配置迁移到其他构建工具的过程中我们就遇到了非常多的问题,他们的配置都很难达到 Webpack 的灵活程度。
- 生产环境的产物优化能力,在启动 Rspack 之前,我们实践了社区内的各种方案,但是他们都面临了生产环境一定程度负优化的情况,例如 拆包拆的不够精细等等。所以生产环境产物优化是我们不可舍弃的功能点。
在明确这四点之后,ByteDance Web Infra 研发团队调研了社区内的所有技术方案,发现并没有完全满足我们需求的,所以ByteDance Web Infra 研发团队决定自研 Rspack。
Rspack 性能分析
和 webpack 的区别
Webpack 是目前最为成熟的构建工具,有着活跃的生态,灵活的配置和丰富的功能,但是其最为人诟病的是其性能问题,尤其在一些大型项目上,构建花费的时间可能会达到几分钟甚至几十分钟,性能问题是目前 webpack 最大的短板。因此 Rspack 解决的问题核心就是 Webpack 的性能问题。 Rspack 比 Webpack 快得益于如下几方面:
- Rust 语言优势: Rspack 使用 Rust 语言编写, 得益于 Rust 的高性能编译器支持, Rust 编译生成的 Native Code 通常比 JavaScript 性能更为高效。
- 高度并行的架构: Webpack 受限于 JavaScript 对多线程的羸弱支持,导致其很难进行高度的并行化计算,而得益于 Rust 语言的并行化的良好支持, Rspack 采用了高度并行化的架构,如模块图生成,代码生成等阶段,都是采用多线程并行执行,这使得其编译性能随着 CPU 核心数的增长而增长,充分挖掘 CPU 的多核优势。
- 内置大部分的功能: 事实上 Webpack 本身的性能足够高效,但是因为 webpack 本身内置了较少的功能,这使得我们在使用 Webpack 做现代 Web App 开发时,通常需要配合很多的 plugin 和 loader 进行使用,而这些 loader 和 plugin 往往是性能的瓶颈,而 Rspack 虽然支持 loader 和 plugin,但是保证绝大部分常用功能都内置在 Rspack 内,从而减小 JS plugin | loader 导致的低性能和通信开销问题。
- 增量编译: 尽管 Rspack 的全量编译足够高效,但是当项目庞大时,全量的编译仍然难以满足 HMR 的性能要求,因此在 HMR 阶段,我们采用的是更为高效的增量编译策略,从而保证,无论你的项目多大,其 HMR 的开销总是控制在合理范围内。
和 Vite 的区别
Vite 提供了很好的开发者体验,但 Vite 在生产构建中依赖了 Rollup ,因此与其他基于 JavaScript 的工具链一样,面临着生产环境的构建性能问题。
另外,Rollup 相较于 webpack 做了一些平衡取舍,在这里同样适用。比如,Rollup 缺失了 webpack 对于拆包的灵活性,即缺失了 optimization.splitChunks 提供的很多功能。
和 esbuild 的区别
我们在内部进行过大规模地将 esbuild 作为通用的 Web App 构建工具的实践,但是遇到如下一些问题:
- 缺乏对 JavaScript HMR 和增量编译的良好支持,这导致大型项目中的 HMR 性能较差。
- 拆包策略也非常原始,难以满足业务复杂多变的拆包优化需求。
和 Turbopack 的区别
Rspack 和 turbopack 都是基于 Rust 实现的 bundler,且都发挥了 Rust 语言的优势。
与 turbopack 不同的是,Rspack 选择了对 Webpack 生态兼容的路线,一方面,这些兼容可能会带来一定的性能开销,但在实际的业务落地中,我们发现对于大部分的应用来说,这些性能开销是可以接受的,另一方面,这些兼容也使得 Rspack 可以更好地与上层的框架和生态进行集成,能够实现业务的渐进式迁移。
和 rollup 的区别
Rspack 和 rollup 虽然都是打包工具,但是两者的侧重领域不同,rollup 更适合用于打包库,而 Rspack 适合用于打包应用。因此 Rspack 对打包应用进行了很多优化,如 HMR、Bundle splitting 等功能,而 rollup 则比 Rspack 的编译产物对库更为友好,如更好的 ESM 产物支持。 社区上也有很多的工具在 rollup 基础上进行了一定的封装,提供了对应用打包更友好的支持,如 vite 和 wmr, 目前 Rspack 比 rollup 有更好的生产环境构建性能。
测量数据
测试于 on Intel(R) Xeon(R) Platinum 8260 CPU @ 2.40GHz 32Core, 64GB of RAM
性能这块主要在这四方分析:
- 冷启动(dev) :从Rspack 启动只需要3.79s、Webpack (with SWC) 居然用了31.25s ,webpack (with babel) 耗时更长,居然耗时 42.61s。这么一对比足足快10倍之多。
- 热更新(根模块变动) :从Rspack 启动只需要570ms、Webpack (with SWC) 居然用了1.67s,webpack (with babel) 耗时更长,居然耗时 1.74s。这么一对比足足快3倍之多。
- 热更新(叶子模块变动):从Rspack 启动只需要560ms、Webpack (with SWC) 居然用了1.53s,webpack (with babel) 耗时更长,居然耗时 1.63s。这么一对比足足快3倍之多。
- 冷构建:从Rspack 启动只需要22.35s、Webpack (with SWC) 居然用了75.05s,webpack (with babel) 耗时更长,居然耗时 160.06s。这么一对比足足将近6倍。
若是一个急性子开发者,估计电脑评估都被砸了
性能测试数据来自Rspack官方,具体如下图更直观:
什么是 Rsbuild ?
官网:https://rsbuild.dev/
Github:https://github.com/web-infra-dev/rsbuild
- Rsbuild 是一个基于 Rspack 的 web 构建工具。
- Rsbuild 是一个增强版的 Rspack CLI,更易用、更开箱即用。
- Rsbuild 是 Rspack 团队对于 web 构建最佳实践的探索和实现。
- Rsbuild 是 Webpack 应用迁移到 Rspack 的最佳方案,减少 90% 配置,构建快 10 倍。
Rsbuild 性能分析
Rsbuild 的构建性能与原生 Rspack 处于同一水平。由于 Rsbuild 内置了更多开箱即用的功能,因此性能数据会略微低于 Rspack。
以下是构建 1000 个 React 组件的时间:
Rsbuild 特性
Rsbuild 具备以下特性:
- 易于配置:Rsbuild 的目标之一,是为 Rspack 用户提供开箱即用的构建能力,使开发者能够在零配置的情况下开发 web 项目。同时,Rsbuild 提供一套语义化的构建配置,以降低 Rspack 配置的学习成本。
- 性能优先:Rsbuild 集成了社区中基于 Rust 的高性能工具,包括 Rspack 和 SWC,以提供一流的构建速度和开发体验。与基于 Webpack 的 Create React App 和 Vue CLI 等工具相比,Rsbuild 提供了 5 ~ 10 倍的构建性能,以及更轻量的依赖体积。
- 插件生态:Rsbuild 内置一个轻量级的插件系统,提供一系列高质量的官方插件。此外,Rsbuild 兼容大部分的 webpack 插件和所有的 Rspack 插件,这意味着你可以在 Rsbuild 中使用社区或公司内沉淀的现有插件,而不需要重写相关代码。
- 产物稳定:Rsbuild 设计时充分考虑了构建产物的稳定性,它的开发环境产物和生产构建产物具备较高的一致性,并自动完成语法降级和 polyfill 注入。Rsbuild 也提供插件来进行类型检查和产物语法检查,以避免线上代码的质量问题和兼容性问题。
- 框架无关:Rsbuild 不与前端 UI 框架耦合,并通过插件来支持 React、Vue 3、Vue 2、Svelte、Solid、Lit 等框架,未来也计划支持社区中更多的 UI 框架。
Rsbuild 生态圈定位
除了作为一个构建工具使用,Rsbuild 也为上层的解决方案提供通用的构建能力,比如 Rspress 和 Modern.js,使ByteDance Web Infra 团队能够专注于开发自己领域特定的能力。
下图说明了 Rsbuild 与生态中其他工具之间的关系:
生态
- Rspack: Rsbuild 的底层打包工具。
- Rspress: 基于 Rsbuild 的静态站点生成器。
- Modern.js: 基于 Rsbuild 的渐进式 React 框架。
- awesome-rspack:与 Rspack 和 Rsbuild 相关的精彩内容列表。
Rsbuild 手把手教你快速上手
环境准备
在开始使用前,你需要安装 Node.js,并保证 Node.js 版本不低于 16,我们推荐使用 Node.js 18 的 LTS 版本。
你可以通过以下命令检查当前使用的 Node.js 版本:
node -v
如果你当前的环境中尚未安装 Node.js,或是安装的版本低于 16,可以通过 nvm 或 fnm 安装需要的版本。
下面是通过 nvm 安装 Node.js 18 LTS 版本的例子:
安装 Node.js 18 的长期支持版本
nvm install 18 --lts
# 将刚安装的 Node.js 18 设置为默认版本
nvm alias default 18
# 切换到刚安装的 Node.js 18
nvm use 18
nvm 和 fnm
nvm 和 fnm 都是 Node.js 版本管理工具。
相对来说,nvm 较为成熟和稳定,而 fnm 是使用 Rust 实现的,比 nvm 提供了更好的性能。
创建 Rsbuild 项目
你可以使用 create-rsbuild 来创建一个 Rsbuild 项目,调用以下命令:
npm create rsbuild@latest
或者
yarn create rsbuild@latest
或者
pnpm create rsbuild@latest
或者
bun create rsbuild@latest
然后按照提示操作即可,你可以选择 create-rsbuild 提供的下列模板:
Rspack 0.4 更新内容
ByteDance Web Infra 团队很高兴地宣布 Rsbuild v0.1 的发布!
Rsbuild 是基于 Rspack 的构建工具,旨在成为增强版的 Rspack CLI,更加容易上手和开箱即用。Rsbuild 是 Webpack 应用迁移到 Rspack 的最佳方案,他能帮助你减少 90% 配置并获得 10 倍构建速度。
目前 Rsbuild 仍在快速迭代中,并计划引入更多强大的新特性。
比如,ByteDance Web Infra 团队正在开发 Rsbuild Doctor,这是一个强大的构建分析工具,可以用于所有 Rspack 和 Webpack 项目。它提供可视化 UI,来帮助开发者分析项目中的构建耗时、重复依赖、代码转换过程等,使构建问题更加容易被定位和解决。
ByteDance Web Infra 团队将在近期发布 Rsbuild Doctor 的第一个可用版本,后续 Rsbuild 会与 Rspack 同步迭代,并计划于 2024 年上半年发布 1.0 版本。
Rspack 0.4 主要变动
停止支持 Node.js 14#
Rspack 不再支持 Node.js 14,现在需要 Node.js 16+。
调整 @rspack/core 为 @rspack/cli 的 peer dependency
@rspack/core 现在是 @rspack/cli 的 peerDependency,而不是直接的依赖关系。这意味着现在您需要手动安装 @rspack/core 和 @rspack/cli。这使得 Rspack 更加接近 webpack。从长远来看,@rspack/cli 的定位将不再是开箱即用的解决方案。我们建议使用 Rsbuild 作为开箱即用的解决方案。
废弃默认转换
experiments.rspackFuture.disableTransformByDefault 在 v0.4.0 中默认启用。对于仍需要旧行为的用户,可以手动将此选项设置为 false。
此功能主要解决三类问题:内置 代码转换功能,目标,和自定义 Rule.type。
- 移除对一些 内置 功能的支持:
- builtins.relay:移动到 rspackExperiments.relay
- builtins.react:移动到 jsc.transform.react
- builtins.emotion:移动到 rspackExperiments.emotion
- builtins.pluginImport:移动到 rspackExperiments.import
- builtins.decorator:移动到 jsc.parser.decorator
- builtins.presetEnv:移动到 jsc.env
module.exports = {
module: {
rules: [
{
test: /.jsx$/,
loader: 'builtin:swc-loader',
options: {
jsc: {
parser: {
syntax: 'ecmascript',
jsx: true,
},
transform: {
react: {
runtime: 'automatic',
},
},
},
rspackExperiments: {
emotion: true, // 与 `builtins` 相同
},
},
type: 'javascript/auto',
},
],
},
experiments: {
rspackFuture: {
disableTransformByDefault: true,
},
},
};
- target(https://www.rspack.dev/config/target) 不再降级用户端代码(包含 node_modules)
module.exports = {
target: ["web", "es5"],
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
loader: 'builtin:swc-loader',
options: {
jsc: {
parser: {
syntax: "ecmascript"
},
+ target: "es5" // 注意:`jsc.target` 和 `env` 不能同时设置。
},
+ env: { // 注意:`jsc.target` 和 `env` 不能同时设置。
+ targets: "chrome >= 48"
+ }
}
type: 'javascript/auto',
},
],
}
};
- 移除非 webpack 兼容的 Rule.type
废弃 builtin.react.refresh
由于在 v0.4.0 中默认启用了
experiments.rspackFuture.disableTransformByDefault,builtin.react.refresh 也已被废弃。现在ByteDance Web Infra 团队建议使用 @
rspack/plugin-react-refresh 来启用 React Fast Refresh。你需要手动安装 @
rspack/plugin-react-refresh 和 react-refresh。
+ const ReactRefreshPlugin = require('@rspack/plugin-react-refresh');
const isDev = process.env.NODE_ENV === 'development';
module.exports = {
// ...
mode: isDev ? 'development' : 'production',
module: {
rules: [
{
test: /.jsx$/,
use: {
loader: 'builtin:swc-loader',
options: {
jsc: {
parser: {
syntax: 'ecmascript',
jsx: true,
},
transform: {
react: {
+ development: isDev,
+ refresh: isDev,
},
},
},
},
},
},
],
},
- builtins: {
- react: {
- refresh: true,
- }
- },
plugins: [
+ isDev && new ReactRefreshPlugin()
].filter(Boolean),
};
Migration Guide
迁移示例 migrate example 展示了如何从 Rspack 0.3.14 迁移到 Rspack 0.4.0
选择@rspack/cli还是Rsbuild?
如果您的应用程序是 CSR 应用程序,则我们强烈建议您使用 Rsbuild 而不是自行配置 Rspack,因为与 @rspack/cli 相比,Rsbuild 更容易使用。
升级 Node.js 版本#
自 0.4.0 起,Rspack 不再支持 Node.js 14,现在仅支持 Node.js 16+。
需要手动安装@rspack/core
#package.json
{
"devDependencies": {
+ "@rspack/core": "0.4.0",
"@rspack/cli": "0.4.0"
}
}
使用内置的builtin:swc-loader支持模块转换
自 0.4.0 起,Rspack 不再默认转换文件,你仍然可以通过如下方式来开启默认转换,
{
experiments: {
rspackFuture: {
disableTransformByDefault: false; // 开启默认转换
}
}
}
官方建议迁移到 builtin:swc-loader 来进行模块转换
对于 React 应用程序,请使用@
rspack/plugin-react-refresh来支持 Fast Refresh
当我们禁用默认转换时,builtin.react.refresh 将无法工作,因此您需要使用 @
rspack/plugin-react-refresh 来启用 Fast Refresh。
迁移 builtin options 到 builtin plugins
Rspack 在 v0.4.0 中废弃了部分 builtin options 并迁移至 rspack 内部插件。
目前,rspack 的内部插件分为两类:
- 与 Webpack 兼容的插件,如 DefinePlugin, ProvidePlugin 等,这部分实现与 webpack 完成了完整的对齐
- Rspack 独有的插件,如 SwcJsMinimizerRspackPlugin, CopyRspackPlugin 等
原有的 builtins.define 可以这样迁移:
+ const rspack = require("@rspack/core")
module.exports = {
- builtins: {
- define: { process.env.NODE_ENV: JSON.stringify(process.env.NODE_ENV) }
- },
+ plugins: [
+ new rspack.DefinePlugin({ process.env.NODE_ENV: JSON.stringify(process.env.NODE_ENV) })
+ ]
}
对于 builtins.html 可以直接迁移到 HtmlRspackPlugin:
+ const rspack = require("@rspack/core")
module.exports = {
- builtins: {
- html: [{ template: "./index.html" }]
- },
+ plugins: [
+ new rspack.HtmlRspackPlugin({ template: "./index.html" })
+ ]
}
当 builtins.html 中存在多个配置,可以创建多个插件实例:
const rspack = require('@rspack/core');
module.exports = {
plugins: [
new rspack.HtmlRspackPlugin({ template: './index.html' }),
new rspack.HtmlRspackPlugin({ template: './foo.html' }),
],
};
对于 builtins.copy 可以直接迁移到 CopyRspackPlugin。
原先的 builtins.minifyOptions 我们提供了
SwcJsMinimizerRspackPlugin:
const rspack = require('@rspack/core');
module.exports = {
optimization: {
minimizer: [
new rspack.SwcJsMinimizerRspackPlugin({
// minimizer 配置
}),
],
},
};
最后
一行代码,可能会创造出下一个让人惊叹的产品;
一个创新,可能会开启一个全新的科技时代;
一份初心,可能会影响到无数人的生活;
无论是在大公司工作,还是在小团队奋斗;
无论是资深的程序员,还是刚刚入行的新手;
每个人的代码,都有力量改变世界。
创作不易,喜欢的老铁们加个关注,点个赞,打个赏,后面会不定期更新干货和技术相关的资讯,速速收藏,谢谢!你们的一个小小举动就是对小编的认可,更是创作的动力。
创作文章的初心是:沉淀、分享和利他。既想写给现在的你,也想贪心写给 10 年、20 年后的工程师们,现在的你站在浪潮之巅,面对魔幻的互联网世界,很容易把一条河流看成整片大海。未来的读者已经知道了这段技术的发展历史,但难免会忽略一些细节。如果未来的工程师们真的创造出了时间旅行机器,可以让你回到现在。那么小编的创作就是你和当年工程师们的接头暗号,你能感知到他们在这个时代的键盘上留下的余温。