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

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

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等核心指标,让优化不再是一次性行为,而是一个长期迭代的体系

相关推荐
方安乐5 分钟前
vite+vue+js项目使用ts报错
前端·javascript·vue.js
韩立23337 分钟前
Vue 3.5 升级指南
前端·vue.js
子兮曰15 分钟前
🚀别再乱写package.json了!这些隐藏技巧让项目管理效率提升300%
前端·javascript·npm
我叫汪枫20 分钟前
Spring Boot图片验证码功能实现详解 - 从零开始到完美运行
java·前端·javascript·css·算法·html
小桥风满袖24 分钟前
极简三分钟ES6 - ES8中async,await
前端·javascript
一直在学习的小白~1 小时前
node_modules 明明写进 .gitignore,却还是被 push/commit 的情况
前端·javascript·vue.js
前端小超超1 小时前
如何配置capacitor 打包的ios app固定竖屏展示?
前端·ios·web app
nightunderblackcat2 小时前
新手向:从零理解LTP中文文本处理
前端·javascript·easyui
kyle~2 小时前
python---PyInstaller(将Python脚本打包为可执行文件)
开发语言·前端·python·qt
User:你的影子2 小时前
WPF ItemsControl 绑定
开发语言·前端·javascript