You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Any code can be split: 通过以上的预加载机制,实现应用内 Any code can be split(一切代码都可以被拆包),且能保证不影响用户体验,让开发者没有了因为单页面资源过大影响应用性能的烦恼,SPA(单页面应用) 也可以拥有极致的首屏幕加载体验和交互体验,🐟与🐻掌兼得。
The text was updated successfully, but these errors were encountered:
AwesomeDevin
changed the title
基于react-route-preload实现的不一样的"代码拆分"+"动态加载"+"预加载"实现应用性能及体验兼得。
基于react-route-preload实现的不一样的"代码拆分"+"动态懒加载"+"预加载"实现应用性能及体验兼得。
Aug 18, 2023
AwesomeDevin
changed the title
基于react-route-preload实现的不一样的"代码拆分"+"动态懒加载"+"预加载"实现应用性能及体验兼得。
「原理篇」基于react-route-preload实现的不一样的"代码拆分"+"动态懒加载"+"预加载"实现应用性能及体验兼得。
Aug 30, 2023
我们看一些针对《如何提升应用首屏加载体验》的文章,提到的必不可少的措施,便是
减少首屏幕加载资源的大小
,而减少资源大小必然会想到按需加载
措施。本文提到的便是一个基于webpack 插件与 react 组件实现的一套研发高度自定义、组件按需加载
的资源预加载方案
. 简单来说是为了通过配置 webpack 插件及少量业务代码即可实现Code Splitting + 组件动态懒加载 + 组件预加载。🧐 为什么要做这么一套预加载方案?它存在的必要性在哪里?🧐
常规组件按需加载方案缺点
渲染时
加载组件资源优点:拆分组件代码,按需加载, 减少首屏的资源加载大小及数量,提升页面首屏渲染速度。
import()
时加载组件资源优点:拆分组件代码,开发者可以更细粒度地控制组件按需加载的时机。
共有缺点:
代码拆分后,
组件资源异步加载存在耗时
,当组件资源特别大或网络不稳定时
都有可能会出现 loading 时间过长导致组件迟迟无法渲染到视图上,以致于影响用户体验
。如图是我们项目中实际出现的场景之一:
由于资源加载存在近
4s
的耗时,组件渲染被延迟,这种情况下,便导致了我们虽然通过减少了首屏资源提升了首屏加载体验,但却让用户在后续使用过程中出现了体验断层
,甚至是页面白屏的情况,这对用户而言是不能接受的用户体验。且这种情况并非网络不好或资源过大等极端情况下才会出现,随着应用使用量的上升,该情况会多次出现,影响用户体验,以下为网络波动的场景之一:
那么如果要保证一个spa应用的后续交互体验,那么就是不拆包,要么就需要引入组件预加载机制。
预加载的必要性:让被懒加载的
组件资源提前进行对应的资源请求
,而不是渲染时请求以减少组件渲染时间,保证应用不会因为组件拆包影响用户体验
。为什么不是react-lodable?
其实 react 社区提供的 react-lodable 解决了以上两个问题:
<Suspense>
,可独立渲染<LazyComponent />
preload
预加载方案,减少异步加载耗时,保证用户体验。但是有个问题是
模块过多
时,侵入式的代码也变多了
,且看起来重复且冗余
,同时被预加载的模块并没有进行统一管理
,后续维护也不会很方便,不直观。那么我们在 webpack 编译层面是可以获取到打包
chunk
的详细信息的,是不是可以在 plugin 层面对按需加载的chunk
进行统一维护
,同时减少侵入式代码
,于是便有了此方案 route-resource-preload, 其具备的特性:拆分模块按需加载,减少应用首屏资源请求大小及数量,提升加载体验.
dynamic
是基于import()
做的一个封装函数。支持组件资源批量自动预加载,同时支持自定义触发时机,如hover到某个组件上、某组件渲染时、出现在视图内时。( Component / Module-Federation / UMD / Svg / Png 等静态资源).
自动预加载步骤:
支持手动调用预加载, 类 react-lodable 的方式,但支持批量.
单个组件手动预加载
多个组件手动预加载
支持React
<Suspense>
,但不依赖。完备的 typescript 类型推导.
DEMO演示
在线体验地址
react.lazy 正常拆包并加载效果.gif
route-resource-preload 拆包并预加载效果.gif
正常懒加载(react.lazy)
普通组件 及 Module-Federationroute-resource-preload 预加载
普通组件 及 Module-Federation加载耗时如下:
方案&流程介绍
该方案基于 @route-resource-preload/webpack-plugin 及 @route-resource-preload/react, 分别对应
构建时
与运行时
:构建时流程图:
构建时
通过 dynamic API 及 webpack plugin 对模块进行拆包的同时,还会将preloadKey(开发者自定义的预加载标识)
、import-module-url(import 模块路径)
、chunk(output产物)
三者之间的关系以json
形式进行保存,并允许应用端访问。生成的JSON文件:
JSON:
开发者基于 JSON,可以判断出
可被预加载的chunk
及已配置预加载的chunk
具体有哪些,同时也能知道插件中配置的预加载标识preloadKey
与chunk
间的映射关系。运行时流程图:
运行时
则是基于构建出的json
,开发者通过设置Preloader 或者是<PreloadLink>
的preloadKey
,对应的相关资源将被预加载,并基于 dynamic API 渲染组件。项目效果演示
1. 真实用户场景打开 Modal( Modal基于 webpack module federation 引入)体验模拟
点击按钮后
,拉取对应的拆包资源及远程 module federation 组件资源,请求完成后渲染组件,存在体验卡顿
,如下图。点击按钮后立即渲染组件,不存在体验卡顿
,如下图。2. 离线场景体验模拟
为了对比效果(有/无预加载)更加直观,以下将采用
离线网络
的场景下进行展示。实现拆包按需加载的用户体验等同于未拆包
。预加载机制存在的必要性
Any code can be split
: 通过以上的预加载机制,实现应用内 Any code can be split(一切代码都可以被拆包),且能保证不影响用户体验,让开发者没有了因为单页面资源过大影响应用性能的烦恼,SPA(单页面应用) 也可以拥有极致的首屏幕加载体验和交互体验,🐟与🐻掌兼得。module federation(模块联邦) 组件预加载
: 对于 webpack 的 module federation(模块联邦)而言,由于 module federation 打包出来的资源默认采用了按需动态加载
的方案,因此当我们渲染一个比较大的 module federation 组件时,也会存在体验卡顿
的情况,这时对该 module federation 组件进行预加载便可解决该体验问题。革新开发者对组件懒加载的了解,减少开发者心智负担
:开发者可以简单粗暴地基于页面
维度对某个路由渲染的组件进行懒加载,不需要再从组件纬度
去分析是因为哪个组件资源包过大导致的体验问题。The text was updated successfully, but these errors were encountered: