通过代码拆分减少 JavaScript 载荷

没有人喜欢等待。 如果网站的加载时间超过 3 秒,超过 50% 的用户会放弃访问

发送较大的 JavaScript 载荷会显著影响网站的速度。不要在加载应用的第一个页面后立即向用户发送所有 JavaScript,而是将 bundle 拆分为多个部分,并在开头仅发送必要的内容。

代码拆分是一种旨在最大限度地缩短启动时间的技术。在启动时提交的 JavaScript 越少,我们就可以通过最大限度地减少此关键时期的主线程工作,让应用更快地实现交互

Core Web Vitals 方面,减少启动时下载的 JavaScript 载荷有助于缩短 Interaction to Next Paint (INP) 时间。原因在于,通过释放主线程,应用可以减少与 JavaScript 解析、编译和执行相关的启动开销,从而更快地响应用户输入。

根据您网站的架构(尤其是如果您的网站严重依赖于客户端呈现),缩减负责呈现标记的 JavaScript 载荷的大小可能会缩短 Largest Contentful Paint (LCP) 时间。如果 LCP 资源延迟被浏览器发现,直到客户端标记完成之后,或者主线程太忙而无法渲染该 LCP 元素,就可能会出现这种情况。这两种情况都可能会延迟网页的 LCP 时间。

测量

如果执行网页上的所有 JavaScript 需要花费大量时间,Lighthouse 会显示审核失败。

失败的 Lighthouse 审核结果,显示脚本执行时间过长。

拆分 JavaScript 软件包,以便在用户加载应用时仅发送初始路由所需的代码。这样可以最大限度地减少需要解析和编译的脚本量,从而缩短网页加载时间。

您可以使用 webpackParcelRollup 等流行的模块打包器使用动态导入拆分软件包。例如,请考虑以下代码段,其中展示了一个在表单提交时触发的 someFunction 方法示例。

import moduleA from "library";

form.addEventListener("submit", e => {
  e.preventDefault();
  someFunction();
});

const someFunction = () => {
  // uses moduleA
}

在这里,someFunction 使用从特定库导入的模块。如果此模块未在其他位置使用,则可以修改代码块,以便仅在用户提交表单时使用动态导入来提取该模块。

form.addEventListener("submit", e => {
  e.preventDefault();
  import('library.moduleA')
    .then(module => module.default) // using the default export
    .then(() => someFunction())
    .catch(handleError());
});

const someFunction = () => {
    // uses moduleA
}

构成模块的代码不会包含在初始软件包中,现在会延迟加载,或者仅在表单提交后需要时才提供给用户。如需进一步提升网页性能,请预加载关键分块,以便优先提取并更快提取它们

虽然前面的代码段是一个简单的示例,但延迟加载第三方依赖项在大型应用中并不常见。通常,第三方依赖项会拆分为单独的供应商软件包,因为它们的更新频率较低,因此可以缓存。您可以详细了解 SplitChunksPlugin 如何帮助您实现这一点。

使用客户端框架时,在路由或组件级别进行拆分是一种更简单的方式,可用于延迟加载应用的不同部分。许多使用 webpack 的热门框架都提供了抽象化功能,可让您更轻松地实现延迟加载,而无需深入研究配置。