如何使用PRPL更快地加载Web应用? - AddyOsmani


PRPL是一种用于结构化和服务Web应用程序和渐进式Web应用程序(PWA)的模式,重点在于改进应用程序的交付和启动性能。这些字母描述了一组快速,可靠,高效的有序步骤:

  • Push (或者 preload): 推送初始路由所需的所有资源- 仅推送这些资源-以确保它们尽可能早地可用
  • Render: 在加载任何其他资源之前,渲染初始路由并使之具有交互性
  • Pre-cache: 预缓存用户可能访问的其他路由的资源,从而在恶劣的网络条件下最大限度地提高对后续请求的响应能力和弹性
  • Lazy load: 懒加载其他路由或者次要资源;关键路由的资源应立即从缓存中加载,而较不常用的资源可以根据请求从网络中获取。


服务器和Service Worker一起为非活动路由预缓存资源。当用户切换路线时,该应用会延迟加载尚未缓存的所有必需资源,并创建所需的视图。

2017年以来,Twitter.com已在生产中使用PRPL模式。下面我们可以看到它们对关键脚本的粒度代码拆分使用,并<link rel=preload>推送它们,以便它们尽可能早地可用:

其他路由按需延迟加载,Twitter在整个用户体验中按需提供40多个块。Twitter还(离线)使用Service Workers对其他路线预先缓存资产,以提高对后续导航的响应能力:

他们的应用程序外壳程序(骨架UI)也处于脱机缓存状态,即使用户通过缓慢或参差不齐的网络连接加载站点,也会立即加载它们:


 
为什么选择PRPL?
使用PRPL构建的应用程序努力做到可靠,快速和引人入胜。除了这些基本目标,PRPL的目标是:

  • 改善应用程序的交互就绪性。通过确保在第一个视图呈现并变为交互式之前,没有多余的资源发送到浏览器来实现此目的。
  • 提高应用程序的缓存效率,尤其是随着时间的推移。它通过以高粒度向浏览器发送资源来做到这一点。当资源被取消捆绑或不太积极地捆绑时,对代码的每次更改都会使更少的缓存无效。
  • 降低开发和部署的复杂性。它依靠应用程序的隐式依赖关系图将每个入口点映射到所需的精确资源集,从而减少或消除了对捆绑和交付的手动管理的需求。

这是一种有用的心态,因为今天的典型应用程序比需要的要重得多。为了帮助在移动Web上提供更好的体验,我们需要首先使应用更轻巧。这意味着要理解并仔细考虑我们包含的所有内容的权重–包括我们自己的代码和我们的依赖项。
但这还不够。我们还以低效的方式交付应用程序,通常会提供包含应用程序全部资源的多合一捆绑包。在用户执行任何操作之前,必须完整地在客户端上接收并处理此捆绑包。展望未来,我们需要构建和服务我们的应用程序,以便:
  • 根据用户的初始请求,我们仅交付和处理支持所请求路线所需的那些资源,以确保我们的应用程序尽快交互
  • 互动后,我们将开始提供必要的其他资源,以确保我们的应用能够立即响应后续用户的请求。
  • 未来对我们应用程序的更新将最大限度地提高效率,并消耗尽可能少的带宽和时间。

  
PRPL规定哪些技术?
PRPL是一种可能以各种方式实现的概念模式,但是通过利用以下现代Web功能的某种组合,可以最轻松有效地实现PRPL:
  • JavaScript Modules这样的现代模块系统,因此工具可以轻松地构建完整的依赖图
  • Service Workers 为后续的应用程序视图预缓存(“安装”)资源(启用脱机优先架构)
  • 预加载,用于尽快交付所需资源。您还可以利用预加载链接头,这些可以被协作服务器拦截并升级为HTTP / 2服务器推送响应。重要的是要记住,尽管功能强大,但Push面临着已知的挑战,但是PRPL使用Service Worker可以避免过度推送的问题(仅对于初始负载为push)。

 
如何实现PRPL模式?
PRPL的很大一部分是颠倒JS捆绑思维方式,并提供尽可能接近编写它们的粒度的资源(至少在功能上独立的模块方面)。您如何实现粒度?
基于路由或基于组件的代码拆分和延迟加载
您已经在将事物编写为组件。也许您正在使用ES模块。对于Webpack,我们使用动态导入和代码拆分将您的代码库拆分为按需加载的块。
默认情况下,诸如Next.jsNuxt.js之类的元框架实现基于路由的代码拆分。如果您使用的是诸如create-react-app之类的工具样板,则需要借助React路由器之类的路由器进行动态导入,才能将基于路由或基于组件的代码拆分添加到您的应用程序中。
对于PRPL的推入/预加载部分,Webpack还支持将预加载作为魔术注释来预加载关键脚本。
可以使用service workers预先缓存剩余路线。利用诸如Workbox之类的服务工作者库来简化为应用程序预先[url=https://developers.google.com/web/tools/workbox/modules/workbox-precaching]缓存[/url]路由和块的过程并不少见。 
 
PRPL使用什么应用程序结构?
PRPL鼓励采用以下结构的单页应用程序(SPA)架构:
  • 应用程序的主要入口点都是由有效路由提供。
    • 文件应该很小,因为它是由不同的URL提供,从而会被多次缓存。入口点中的所有资源URL都必须是绝对的,因为它可以从非顶级URL提供。
  • shell或app-shell,其中包括顶级应用程序逻辑,路由器等。
  • 延迟加载应用程序的片段fragment。
    • 片段可以代表特定视图的代码,也可以延迟加载的其他代码(例如,主应用程序的部分不需要第一次绘制:例如菜单,直到用户与应用程序交互才显示它)。Shell负责根据需要动态导入片段。


应用程序应根据需要调用动态导入以延迟加载片段。例如,当用户更改为新路由时,它将导入与该路由关联的片段。这可能会向服务器发起新请求,或者只是从缓存中加载资源。
 

结论
除了针对PWA的基本目标和标准之外,PRPL还致力于针对以下方面进行优化:

  • 交互准备程度最低-特别是在首次使用时(无论进入点如何)
  • 最大的缓存效率,尤其是随着更新的发布,随着时间的推移
  • 开发和部署简单

自2016年推出以来,PRPL是一种已被大规模使用的模式,并且仍然是值得为您的应用程序加载值得考虑的有价值的方法。