SPA单页面首屏加载优化方案

张开发
2026/4/10 2:43:53 15 分钟阅读

分享文章

SPA单页面首屏加载优化方案
一、什么是首屏加载首屏时间First Contentful Paint指的是浏览器从响应用户输入网址地址到首屏内容渲染完成的时间此时整个网页不一定要全部渲染完成但需要展示当前视窗需要的内容首屏加载可以说是用户体验中最重要的环节关于计算首屏时间利用performance.timing提供的数据通过DOMContentLoad或者performance来计算出首屏时间// 方案一document.addEventListener(DOMContentLoaded, (event) {console.log(first contentful painting);});// 方案二performance.getEntriesByName(first-contentful-paint)[0].startTime// performance.getEntriesByName(first-contentful-paint)[0]// 会返回一个 PerformancePaintTiming的实例结构如下{name: first-contentful-paint,entryType: paint,startTime: 507.80000002123415,duration: 0,};二、加载慢的原因在页面渲染的过程导致加载速度慢的因素可能如下网络延时问题资源文件体积是否过大资源是否重复发送请求去加载了加载脚本的时候渲染内容堵塞了三、解决方案常见的几种SPA首屏优化方式减小入口文件积静态资源本地缓存UI框架按需加载图片资源的压缩组件重复打包开启GZip压缩使用SSR异步组件 Suspense推荐用于大组件懒加载减小入口文件体积常用的手段是路由懒加载把不同路由对应的组件分割成不同的代码块待路由被请求的时候会单独打包路由使得入口文件变小加载速度大大增加在vue-router配置路由的时候采用动态加载路由的形式routes:[ path: Blogs, name: ShowBlogs, component: () import(./components/ShowBlogs.vue) ]以函数的形式加载路由这样就可以把各自的路由文件分别打包只有在解析给定的路由时才会加载路由组件静态资源本地缓存后端返回资源问题采用HTTP缓存设置Cache-ControlLast-ModifiedEtag等响应头采用Service Worker离线缓存前端合理利用localStorageUI框架按需加载在日常使用UI框架例如element-UI、或者antd我们经常性直接饮用整个UI库import ElementUI from element-ui Vue.use(ElementUI)但实际上我用到的组件只有按钮分页表格输入与警告 所以我们要按需引用import { Button, Input, Pagination, Table, TableColumn, MessageBox } from element-ui; Vue.use(Button) Vue.use(Input) Vue.use(Pagination)组件重复打包假设A.js文件是一个常用的库现在有多个路由使用了A.js文件这就造成了重复下载解决方案在webpack的config文件中修改CommonsChunkPlugin的配置minChunks: 3minChunks为3表示会把使用3次及以上的包抽离出来放进公共依赖文件避免了重复加载组件图片资源的压缩图片资源虽然不在编码过程中但它却是对页面性能影响最大的因素对于所有的图片资源我们可以进行适当的压缩对页面上使用到的icon可以使用在线字体图标或者精灵图将众多小图标合并到同一张图上用以减轻http请求压力。图片懒加载当图片出现在页面中时才去请求图片资源// 滚动时触发 window.addEventListener(scroll, function() { const imgs document.querySelectorAll(.lazy) for (let img of imgs) { const rect img.getBoundingClientRect() // 用来获取元素位置和大小 // 图片顶部 屏幕高度 图片底部 0 if (rect.top window.innerHeight rect.bottom 0) { img.src img.dataset.src // 赋值真实地址 img.classList.remove(lazy) // 移除此类避免重复加载 } } })IntersectionObserver 实现图片懒加载img classlazy>cnmp i compression-webpack-plugin -D在vue.congig.js中引入并修改webpack配置const CompressionPlugin require(compression-webpack-plugin) configureWebpack: (config) { if (process.env.NODE_ENV production) { // 为生产环境修改配置... config.mode production return { plugins: [new CompressionPlugin({ test: /\.js$|\.html$|\.css/, //匹配文件名 threshold: 10240, //对超过10k的数据进行压缩 deleteOriginalAssets: false //是否删除原文件 })] } }在服务器我们也要做相应的配置 如果发送请求的浏览器支持gzip就发送给它gzip格式的文件 我的服务器是用express框架搭建的 只要安装一下compression就能使用const compression require(compression) app.use(compression()) // 在其他中间件使用之前调用使用SSRSSRServer side 也就是服务端渲染组件或页面通过服务器生成html字符串再发送到浏览器从头搭建一个服务端渲染是很复杂的vue应用建议使用Nuxt.js实现服务端渲染异步组件 Suspense推荐用于大组件懒加载!-- Parent.vue -- template Suspense template #default AsyncComponent / /template template #fallback div加载中.../div /template /Suspense /template script setup import { defineAsyncComponent } from vue const AsyncComponent defineAsyncComponent(() import(./AsyncComponent.vue)) /script组件AsyncComponent.vue会被单独打包首次使用时才加载提升首屏性能 ‌2. 异步 setup Suspense适用于组件内部需异步获取数据!-- AsyncComponent.vue -- script setup const response await fetch(/api/data) const data await response.json() /script template div{{ data }}/div /template!-- Parent.vue -- template Suspense template #default AsyncComponent / /template template #fallback p正在加载内容.../p /template /Suspense /template注意使用async setup()时‌必须用Suspense包裹‌否则会报错或出现白屏 ‌。关键特性‌自动管理加载状态‌Suspense会监听所有嵌套的异步依赖只有当‌所有异步组件/数据都准备就绪‌时才渲染#default内容 ‌。‌支持多级嵌套‌可嵌套多个Suspense实现分阶段加载提示 ‌。‌事件支持‌提供pending、fallback、resolve事件便于自定义加载逻辑如全局加载条‌。‌错误处理‌可结合onErrorCaptured或errorComponent选项处理加载失败 ‌。注意事项❌ ‌不要在生命周期钩子如onMounted中使用async/await来替代异步组件‌否则无法触发Suspense的加载状态 ‌。⚠️ ‌Suspense仅对异步组件或async setup()生效‌普通Promise不会触发其逻辑 ‌。 ‌Suspense是实验性功能‌Vue 3.2 稳定但已在生产环境中广泛使用 ‌四、小结减少首屏渲染时间的方法有很多总的来讲可以分成两大部分 资源加载优化和页面渲染优化下图是更为全面的首屏优化的方案

更多文章