前端如何处理首屏优化问题

用户普遍反馈项目首屏加载比较满,所以我做了完整的一次性能分析,定位到几个关键的瓶颈;

1.问题主要在js bundle体积过大(3.2mb) 和首屏并发请求过多(12个);

2.bundle问题做了代码分割和懒加载,路由改成动态的import、三方库按需引入。

针对接口就是梳理了下数据依赖,把12个借口合并成2个关键接口。

所以首屏加载时间从4.2秒优化到1.8秒,fcp指标提升了60%,效果显著

如何分析出的这些瓶颈的?

1.performance:

浏览器吧检查调出来有一个performance那一栏,点击录制,然后操作页面,再stop停止录制,就会出现一个火焰图。

发现主线程被大量的js解析任务阻塞(黄色部分占据很大一个比例),同时用Lighthouse跑分,量化出FCP和LCP指标确实比较低。

2.构建分析:

用webpack-buldle-analyzer对打包产物进行可视化分析,一下就可以看出moment.js这种库占了韩大的体积,就改用更轻量的days.js

使用:yarn add --dev webpack-bundle-analyzer

通过 Webpack 配置插件(推荐)

在你的 webpack.config.js(或者 webpack.prod.js等构建配置文件)中引入并使用该插件:

示例代码:

const BundleAnalyzerPlugin =

require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {

// ...你的其他 webpack 配置

plugins: [ // 添加这个插件(不传参数默认会在构建后自动打开分析页面)

new BundleAnalyzerPlugin()

] };

🧠 如何操作:

  • ∙ 运行 webpack 构建后,​​该插件会启动一个本地 HTTP 服务器(通常是 http://localhost:8888)​​

  • ∙ 然后​​自动打开浏览器​​,展示打包结果的可视化分析页面

  • ∙ 页面中以​​矩形树图(Treemap)的形式展示各个模块的大小与依赖关系​​

如何解决细节

组件方面:

对于一些体积比较大,但是不是一进入页面理解展示的组件 通过动态import()方式进行分割;

代码分离

配置方面:

在webpack配置层面,使用了splitChunks,将常用的第三方库和公共模块抽离成独立的chunk,以便浏览器长期缓存'

将代码分离到不同的bundle中,之后我们可以按需加载,或者并行加载这些文件

默认情况下,所有的JavaScript代码(业务代码、第三方依赖、暂时没有用到的模块)在首页全部都加载,就会影响首页的加载速度

代码分离可以分出出更小的bundle,以及控制资源加载优先级,提供代码的加载性能

这里通过splitChunksPlugin来实现,该插件webpack已经默认安装和集成,只需要配置即可

默认配置中,chunks仅仅针对于异步(async)请求,我们可以设置为initial或者all

复制代码
module.exports = {
    ...
    optimization:{
        splitChunks:{
            chunks:"all"
        }
    }
}

splitChunks主要属性有如下:

  • Chunks,对同步代码还是异步代码进行处理
  • minSize: 拆分包的大小, 至少为minSize,如何包的大小不超过minSize,这个包不会拆分
  • maxSize: 将大于maxSize的包,拆分为不小于minSize的包
  • minChunks:被引入的次数,默认是1

如何保证代码分割后的用户体验

1.我加了一个loading等待的效果,缓解用户的等待焦虑;或者suspense的fallback设计一个骨架屏

import React, { Suspense, lazy } from 'react';

// 动态导入组件 => 会生成单独的 chunk

const HomePage = lazy(() => import('./pages/HomePage'));

function App() {

return (

<Suspense fallback={<div>🌀 页面加载中,请稍候...</div>}>

<HomePage />

</Suspense>

);

}

2.我还弄了一个预加载,就是在用户鼠标hover导航菜单时候,以前与加载对应页面的chunk,让页面条环更快

实现思路:

  • ∙ 不是直接调用 import('./Page')(这会立即加载),而是将动态导入函数保存下来,在 hover 事件里 ​​手动调用它​​。

  • ∙ React.lazy 的 import()是自动执行的,所以我们需要 ​​自行封装动态 import,以拿到 Promise 函数​​,实现"按需手动触发"。

// 不使用 React.lazy,而是自己封装动态加载函数

const getHomePage = () => import('./pages/HomePage');

// 在导航菜单 hover 时预加载

function Navigation() {

const handleMouseEnter = () => {

// hover 时触发 chunk 加载

getHomePage(); // 这里会开始下载对应 chunk

};

return (

<nav>

<span onMouseEnter={handleMouseEnter}>首页</span>

</nav>

);

}

// 真正渲染组件时仍然用 React.lazy + Suspense

const HomePage = React.lazy(getHomePage);

function App() {

return (

<Suspense fallback={<div>加载中...</div>}>

<HomePage />

</Suspense>

);

}

3.用错误边界包裹了动态加载的组件,这样即使整个chunk因为网络问题加载失败,整个应用也不会白屏,给他展示一个toast提示。

除了这些 还有什么其他可以首屏优化的,协同团队做了基础设施层的优化;

1.将所有静态资源部书到cdn的边缘节点,开启http/2协议和gzip压缩

2.和后端同学一起,为核心api增加额redis缓存,并对曼查询的数据库表增加了索引,给接口响应时间从800ms降低到200ms

3。建立监控体系:部署了前端性能监控系统,能够持续追踪core web vitals等核心指标,让优化不再是一次性行为,而是一个长期迭代的体系

相关推荐
Data analyse4563 小时前
App埋点版本兼容的字段迁移校验
大数据·运维·服务器·前端·数据库·数据分析
todoitbo4 小时前
本来只想给内网开个口子,Natapp 却多给了一道防护
前端·javascript·vue.js·内网穿透·网络防护·natapp
会灭火的程序员4 小时前
SuperMap AgentX Server智能体接入WEB应用技术文档
前端·supermap·agentx·agentx server
CRMEB4 小时前
商品 SKU 设计,从简单规格到多规格踩过什么
java·前端·数据库·开源
Chloe.Zz4 小时前
一篇入门Agent
开发语言·前端·javascript
java1234_小锋4 小时前
【技术专题】HTML5 网页技术 - HTML5 表格标签
前端·html·html5
雪芽蓝域zzs4 小时前
JS 项目转 TS 项目(Vue3 + 若依这类后台项目)完整改造清单
前端·vue.js
定栓4 小时前
Webpack迁到Vite第四节:SVG 图标系统
前端·webpack·node.js
Dovis(誓平步青云)4 小时前
车辆进入隧道后信号断开,座舱旅程怎样补回事件
java·开发语言·前端·数据库·电脑