本节内容摘自以下链接的内容,并受 CC BY 4.0 许可证的约束。
以下内容可以假设为基于原始内容的修改和删除结果,除非另有说明。
Rspack 支持代码拆分,它允许将代码拆分为其他块。您可以完全控制生成资产的大小和数量,从而在加载时间方面获得性能改进。
在这里,我们介绍一个称为“Chunk”的概念,它代表浏览器需要加载的资源。
Rspack 使用import() 语法,该语法符合 ECMAScript 对动态导入的提案。
Rspack 不支持 `require.ensure`。
在 `index.js` 中,我们通过 `import()` 动态导入两个模块,从而将其拆分为一个新的块。
现在我们构建这个项目,我们会得到 3 个块,`src_bar_js.js`、`src_foo_js.js` 和 `main.js`,如果你查看它们,你会发现 `shared.js` 存在于 `src_bar_js.js` 和 `src_foo_js.js` 中,我们将在后面的章节中删除重复的模块。
虽然 `shared.js` 存在于 2 个块中,但它只执行一次,您不必担心多个实例的问题。
这是最简单也是最直观的代码拆分方法。但是,这种方法需要我们手动配置 Rspack。让我们从查看如何从多个入口点拆分多个块开始。
这将产生以下构建结果
同样,如果你查看它们,你会发现它们都包含重复的 `shared.js`。
上面提到的代码分割非常直观,但是大多数现代浏览器都支持并发网络请求。如果我们将 SPA 应用程序的每个页面划分为单个块,并且当用户切换页面时,他们请求一个更大的块,这显然没有很好地利用浏览器处理并发网络请求的能力。因此,我们可以将块分解为更小的块。当我们需要请求此块时,我们改为同时请求这些较小的块,这将使浏览器的请求更有效。
Rspack 默认将 `node_modules` 目录中的文件和重复模块进行拆分,将这些模块从它们的原始块中提取到一个单独的新块中。那么为什么在上面的示例中 `shared.js` 仍然重复出现在多个块中?这是因为我们示例中的 `shared.js` 尺寸非常小。如果将非常小的模块拆分为单独的块供浏览器加载,实际上可能会减慢加载过程。
我们可以将最小拆分大小配置为 0,以允许 `shared.js` 单独提取。
重建后,你会发现 `shared.js` 已经被单独提取出来了,并且在产品中有一个额外的块包含 `shared.js`。
我们可以指定某些模块要强制分组到单个块中,例如以下配置
使用上述配置,所有路径中包含 `some-lib` 目录的文件都可以提取到名为 `lib` 的单个块中。如果 `some-lib` 中的模块很少更改,那么此块将始终命中用户的浏览器缓存,因此这种经过深思熟虑的配置可以提高缓存命中率。
但是,将 `some-lib` 分割成独立的块也可能存在缺点。假设一个块只依赖于 `some-lib` 中的一个非常小的文件,但是由于 `some-lib` 的所有文件都拆分到一个单独的块中,因此此块必须依赖于整个 `some-lib` 块,导致更大的加载量。因此,在使用 cacheGroups.{cacheGroup}.name 时,需要仔细考虑。
以下示例展示了 cacheGroup 的 `name` 配置的效果。
在声明导入时使用这些内联指令允许 Rspack 输出“资源提示”,告诉浏览器以下内容:
一个例子是拥有一个 `HomePage` 组件,它呈现一个 `LoginButton` 组件,然后在被点击后按需加载一个 `LoginModal` 组件。
这将导致在页面的头部添加 `<link rel="prefetch" href="login-modal-chunk.js">`,它将指示浏览器在空闲时间预取 `login-modal-chunk.js` 文件。
Rspack 将在父块加载后添加预取提示。
预加载指令与预取相比有一些区别。
一个例子是拥有一个 `Component`,它始终依赖于一个应该在单独的块中的大型库。
让我们想象一个 `ChartComponent` 组件,它需要一个巨大的 `ChartingLibrary`。它在渲染时显示一个 `LoadingIndicator`,并立即按需导入 `ChartingLibrary`。
当请求使用 `ChartComponent` 的页面时,`charting-library-chunk` 也通过 `<link rel="preload">` 被请求。假设页面块更小并且更快地完成,页面将显示一个 `LoadingIndicator`,直到已经请求的 `charting-library-chunk` 完成。这将节省一些加载时间,因为它只需要一次往返而不是两次。尤其是在高延迟环境中。
不正确地使用 webpackPreload 实际上会损害性能,因此在使用它时要小心。
有时您需要对预加载有自己的控制。例如,可以将任何动态导入的预加载通过异步脚本完成。这在流式服务器端渲染的情况下很有用。
如果在 Rspack 开始自行加载脚本之前脚本加载失败(Rspack 创建一个脚本标签来加载其代码,如果该脚本不在页面上),那么 catch 处理程序将不会在 chunkLoadTimeout 超时之前启动。这种行为可能出乎意料。但这是可以解释的——Rspack 无法抛出任何错误,因为 Rspack 不知道脚本失败了。Rspack 将在错误发生后立即为脚本添加 onerror 处理程序。
为了防止出现此问题,您可以添加自己的 onerror 处理程序,以便在出现任何错误时删除脚本。
在这种情况下,错误的脚本将被删除。Rspack 将创建自己的脚本,并且任何错误都将在没有超时的情况下被处理。