Rspack v0.7 发布公告

2024 年 5 月 28 日

Rspack v0.7 版本已经正式发布!

这是 Rspack v1.0 版本发布前的最后一个 minor 版本,此后 Rspack 团队将投入到 v1.0 版本的开发中,并致力于尽快推出 Rspack v1.0 alpha 版本。

在 Rspack v0.7 中,值得关注的变更如下:

支持 Lazy Compilation

Rspack v0.7 支持了 lazy compilation(懒编译),它对于提高多入口应用(MPA)或大型单页面应用(SPA)的 dev 启动性能非常有帮助。

什么是 Lazy Compilation

Lazy compilation 是一个提升启动性能的良好手段,它可以按需编译模块,而不是在启动时就编译所有模块。这意味着开发者在启动 dev server 时,可以很快看到应用运行,并分次构建所需的模块。

为什么需要 Lazy Compilation

尽管 Rspack 本身具备良好的性能,但是面对具有大量模块的应用,其整体构建时间仍然可能不够理想。这是因为应用中的模块需要经过不同 loader 的编译,包括 postcss-loadersass-loadervue-loader 等,它们都会产生额外的编译开销。

在启用 lazy compilation 的情况下,Rspack 仅会编译被请求的「页面入口」和「动态 import 模块」,这可以显著减少开发启动时编译的模块数量,从而提升启动时间。

想象下面的场景:

你的团队在开发一个包含几十个页面的 MPA 应用,大部分时候,你只参与开发其中的某几个页面,并不需要构建其他页面的代码。此时,你可以启用 lazy compilation,使 Rspack 仅编译你访问的页面所引用的模块。

在开启 lazy compilation 后,Rspack 会将「页面入口」和「dynamic import」作为分割点,例如:

src/a.js
if (someCondition) {
  import('./b.js');
}

当我们编译 a.js 时,Rspack 会将 b.js 当成一个空模块,假装用户从未在其中编写过任何代码。一旦我们需要访问 b.js,Rspack 就用其原始内容填充 b.js 模块,有点类似于用户瞬间编写了这部分代码。

以 Rspack 文档站为例,它包含多个页面,当开启 lazy compilation 后,只有访问到的入口及其依赖的模块会被构建,这极大的提升了启动速度,启动时间从 2.1s 降至 0.05s。

当开发者访问网站的某一个页面时,会触发该页面的构建,且这次构建的时间依然会明显小于完整的构建时间。

lazy-compilation-compare

如何使用

现在,你可以通过 experiments.lazyCompilation 配置项来开启懒编译功能:

rspack.config.js
const isDev = process.env.NODE_ENV === 'development';

module.exports = {
  experiments: {
    lazyCompilation: isDev,
  },
};

注意,当前 lazy compilation 是对齐 webpack 实现的,并且仍处于实验性阶段。在部分场景下,lazy compilation 可能无法按照预期工作,或是性能提升不明显。

我们将持续完善 lazy compilation 在不同场景下的可用性,使之达到更稳定的状态。如果你在使用过程中遇到任何问题,欢迎通过 GitHub Issues 向我们反馈。

更快的 CSS 构建

在 v0.7 版本中,我们对 experiments.css 的内部实现进行了重构。

针对 CSS 依赖分析,我们使用 Rust 开发了 css-module-lexer,这是一个针对 CSS Modules 的高性能 lexer,能够解析 CSS 或 CSS Modules 并返回其依赖元信息。

在接入 css-module-lexer 后,Rspack 能够支持更复杂的 CSS Modules 语法,对齐了 webpack 的 css-loader 的行为。比如能够支持以下 CSS Modules 语法:

style.module.css
:local(.parent):global(.child) > ul {
  color: red;
}

下图是重构前后的 CSS 解析流程示意:

rspack-css-lexer

同时,css-module-lexer 也给 Rspack 的 experiments.css 带来了显著的性能提升。经过性能测试,bootstrap.css 打包速度提升约 4 倍:

  • 重构前:约 84ms(分析 CSS 依赖约 71ms)
  • 重构后:约 25ms(分析 CSS 依赖约 11ms)

不兼容更新

Rspack 会在 1.0 版本前,逐步下线所有不稳定的 API 和配置,更多配置 / API / 默认行为将与 webpack 保持一致。

移除一些不稳定的 JavaScript API

Rspack 初期暴露了一些预期仅供内部使用且不稳定的 API,如 compiler.compilationcompiler.builtinPlugins 等,这些 API 并不稳定且无法在 webpack 中使用。

在 v0.7 版本中,我们重新整理了目前暴露的 API 及其接口定义。如果你有使用到这些 API,你需要进行一些调整,切换到与 webpack 一致的实现方式。

以下 API 已废弃:

  • compiler.builtinPlugins
  • compiler.compilation
  • compiler.compilationParams
  • compiler.getAsset(name)
  • statsError.formatted
  • statsWarning.formatted
  • ...

关于废弃 API 的详细情况可参考 rspack#6448rspack#6505

CSS @import 规则须先于其他规则

0.7 版本我们对 experiments.css 的内部实现进行了部分重构。

重构后,当 @import 不在最顶部时,会得到如下报错,此时需要你手动将 @import 规则调整到顶部。

ERROR in ./src/main.css
  × Module parse failed:
  ╰─▶   × CSS parsing warning: Any '@import' rules must precede all other rules
         ╭─[4:1]
       4};
       5       6 │ @import 'bootstrap/dist/css/bootstrap.css';
         · ───────
       7       8         ╰────

  help:
        You may need an appropriate loader to handle this file type.

移除 builtins 以及 experiments.rspackFuture.newTreeshaking

v0.7 已移除 builtins.treeShaking (oldTreeShaking) 和 experiments.rspackFuture.newTreeshaking (新 tree shaking 开关) 配置,将旧的 tree shaking 功能彻底下线。

移除 resolve.browserField

该配置为 resolve.aliasFields = ["browser"] 的简写,由于 Rspack 已经支持 resolve.aliasFields,所以不再需要该配置。

移除 experiments.newSplitChunks

该配置用于开启新的 splitChunks 实现,由于 Rspack 已经默认使用新的 splitChunks 实现,所以不再需要该配置。

移除 snapshot

该配置用于配置 cache snapshot 的行为。在 Rspack 目前的增量架构下,cache 不再依赖 snapshot,所以不再需要该配置。

移除 generator.css.exportsConvention

该配置用于控制 experiments.css 的 CSS 模块导出的命名形式,仅对于模块类型为 css/module 的模块才会有导出,对于模块类型为 css 的模块并不存在导出,所以不需要该配置。

升级 SWC 到 0.91.x

升级 Rust crate swc_core0.91.x,这会对使用 SWC Wasm 插件的用户产生影响。

迁移指南

升级 SWC 插件

在 v0.7 中,Rust crate swc_core 的版本升级到 0.91.x,使用到的 SWC Wasm 插件需要确保其使用的 swc_core 的版本一致性,否则可能产生无法预知的问题。

详情请参考文档

替换 resolve.browserField 为 resolve.aliasFields

如果你之前配置了 resolve.browserField,则需要使用 resolve.aliasFields 进行替换:

  • resolve.browserField = true 替换为 resolve.aliasFields = ["browser"]
  • resolve.browserField = false 替换为 resolve.aliasFields = []

移除 generator.css.exportsConvention

如果你之前配置了 module.generator.css.exportsConvention 或在 module.rule 中配置了 generator.exportsConvention,只需要删除该配置即可。

Rsbuild v0.7

Rsbuild v0.7 已与 Rspack v0.7 同步发布,请阅读 Rsbuild v0.7 发布 了解更多。