通过代码拆分减少 JavaScript 负载

158 阅读3分钟

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

发送大量JavaScript有效负载会显著影响站点的速度。不要在加载应用程序的第一个页面时就将所有JavaScript发送给用户,而是将包拆分为多个部分,只在最开始时发送必要的内容。

为什么代码拆分是有益的?

代码分割是一种寻求最小化启动时间的技术。当我们在启动时交付更少的JavaScript时,我们可以通过在这个关键时期最小化主线程工作来使应用程序的交互性更快(interactive faster)。

对于 Core Web Vitals (Core Web Vitals),减少在启动时下载的 JavaScript 有效负载将有助于更好的首次输入延迟 (First Input Delay (FID)) 和与下一次绘制 (Interaction to Next Paint (INP)) 的交互时间。 这背后的原因是,通过释放主线程,应用程序能够通过减少 JavaScript 解析、编译和执行相关的启动成本来更快地响应用户输入。

根据您网站的架构(特别是如果您的网站严重依赖客户端渲染),减少负责渲染标记的 JavaScript 有效负载的大小可能会提高最大内容绘制 (Largest Contentful Paint (LCP)) 时间。 当浏览器延迟发现 LCP 资源(delayed in being discovered by the browser)直到客户端标记完成之后,或者当主线程太忙而无法呈现该 LCP (render that LCP element)元素时,可能会发生这种情况。 这两种情况都可以延迟页面的 LCP 时间。

Important

如果您的网站仅依赖于客户端呈现,则应寻求使用服务器端呈现 (Server-Side Rendering (SSR)) 来确保服务器向客户端发送有意义的标记以响应导航请求。 这可以帮助浏览器预加载扫描器(browser preload scanner)更有效地机会性地获取资源(more effectively)。

措施

当花费大量时间执行页面上的所有 JavaScript 时,Lighthouse 会显示审核失败。

拆分 JavaScript 包以仅在用户加载应用程序时发送初始路由所需的代码。 这最大限度地减少了需要解析和编译的脚本数量,从而加快页面加载时间。

webpack, Parcel, and Rollup 等流行的模块打包器允许您使用动态导入(dynamic imports)来拆分包。 例如,考虑以下代码片段,它显示了在提交表单时触发的 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
}

构成模块的代码不会被包含到初始包中,现在是惰性加载的,或者只在表单提交后需要时提供给用户。为了进一步提高页面性能,可以预加载关键块,以确定优先级并更快地获取它们(preload critical chunks to prioritize and fetch them sooner)。

尽管前面的代码片段是一个简单的示例,但是在大型应用程序中,延迟加载第三方依赖项并不是常见的模式。通常,第三方依赖被分割成一个独立的供应商包,可以缓存,因为它们不经常更新。你可以阅读更多关于 SplitChunksPlugin 如何帮助你做到这一点。

在使用客户端框架时,在路由或组件级别进行拆分是延迟加载应用程序不同部分的一种更简单的方法。许多使用webpack的流行框架提供了抽象,使惰性加载比自己钻研配置更容易。

performance