当前位置: 首页 > web >正文

Vue 项目首屏加载速度优化

Vue 项目首屏加载从 5s 到 1.5s:4 步落地优化方案,附完整代码 + 数据对比

前段时间我在做一个活动时,打包加载后发现打开页面要等半天,经过几天的优化,最终将首屏加载时间从5秒压到 1.5 秒。

这篇文章会把整个优化过程拆解成「文件分析→代码解决→验证」三步,每个方案都附完整代码前后数据对比,新手也能直接复用。

1. 打包体积分析:看「哪些文件在拖后腿」

操作步骤(Vue CLI/Vite 通用):

  • Vue CLI 项目:执行 npm run build -- --report;
  • Vite 项目:执行 npm run build -- --report(需先在 vite.config.js 中开启 build.report: true);
  • 打包完成后,dist 目录会生成 report.html,打开后能看到「打包体积占比图」。

我的项目诊断结果:

问题类型

具体表现

占比

路由未懒加载

所有路由组件打包进 app.js,导致初始 JS 体积过大

35%

UI 库完整引入

Element Plus 完整引入(600KB),但仅用 5 个组件

30%

图片未优化

banner 图未压缩(2.3MB),小图标未转 Base64

25%

公共代码未拆分

Vue、lodash 等第三方库重复打包

10%

明确了这 4 个核心问题,接下来的优化就有了方向 —— 不用贪多,解决这 4 个问题,首屏加载就能提速 60% 以上。

2. 4种方法可以优化:每个方案都附代码 + 效果

方案 1:路由懒加载

原理:

默认情况下,Vue 会把所有路由组件打包进「app.js」,导致初始加载时要下载全部组件;懒加载则是「用户访问哪个路由,才下载哪个组件的 JS」,能直接减少初始 JS 体积。

代码对比:

// 优化前:同步加载(所有组件打包进app.js)import Home from './views/Home.vue'import About from './views/About.vue'const routes = [{ path: '/', component: Home },{ path: '/about', component: About }]// 优化后:懒加载(按需下载)const routes = [// 动态import语法,访问时才加载{ path: '/', component: () => import('./views/Home.vue') },{ path: '/about', component: () => import('./views/About.vue') }]

效果对比:

指标

优化前

优化后

提升

初始 JS 体积

1.8MB

1.08MB

40%

首屏加载时间

5.0s

3.2s

36%

避坑提示:

  • 不要给「首屏路由」(如 Home)做懒加载,否则会增加首屏加载的请求数;
方案 2:UI 库按需引入(减少 200KB,自动生效)

原理:

完整引入 UI 库(如 Element Plus)会包含大量未使用的组件和样式(比如你只用了按钮,却加载了日历、表格等组件),按需引入能只打包「实际使用的组件」。

以 Element Plus 为例(Vite 项目):

  1. 安装按需引入插件:
npm install unplugin-vue-components unplugin-auto-import -D
  1. 在 vite.config.js 中配置:
import { defineConfig } from 'vite'import Vue from '@vitejs/plugin-vue'// 1. 引入按需引入插件import AutoImport from 'unplugin-auto-import/vite'import Components from 'unplugin-vue-components/vite'import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'export default defineConfig({plugins: [Vue(),// 2. 配置插件AutoImport({resolvers: [ElementPlusResolver()], // 自动引入Element Plus的API(如ElMessage)}),Components({resolvers: [ElementPlusResolver()], // 自动引入Element Plus的组件(如ElButton)}),],})
  1. 在组件中直接使用,无需手动 import:
<template><!-- 无需引入ElButton,插件会自动处理 --><el-button type="primary" @click="showMessage">提交</el-button></template><script setup>// 无需引入ElMessage,插件会自动引入const showMessage = () => {ElMessage.success('提交成功')}</script>

效果对比:

指标

优化前

优化后

提升

Element Plus 体积

600KB

400KB

33%

首屏加载时间

3.2s

2.8s

12.5%

避坑提示:

  • 如果使用 Vue CLI,配置方式略有不同(需在 vue.config.js 中配置);
  • 部分 UI 库的「样式」需要单独按需引入(如 Ant Design Vue),需查看官方文档。
方案 3:图片优化(首屏资源减少 50%,用户感知最明显)

图片是首屏加载的「重灾区」—— 我的项目中,图片占了首屏资源体积的 50%,优化后直接减少了 1.6MB。

推荐 3 个必做的图片优化手段,覆盖 90% 的场景:

1. 小图转 Base64(减少 HTTP 请求)

  • 原理:小于 10KB 的图片(如图标、小按钮)转为 Base64 后,会嵌入 HTML/JS 中,无需额外发请求;
  • 实现(Vite 自动处理):
// vite.config.js
export default defineConfig({build: {assetsInlineLimit: 10240, // 10KB以下图片自动转Base64(默认是4KB)},
})

2. 大图用 WebP 格式(体积减少 50%)

  • 原理:WebP 格式比 JPG/PNG 体积小 30%~50%,且支持透明和动图;
  • 实现:
  1. 用工具将图片转为 WebP(推荐 TinyPNG、Squoosh);
  2. 在 Vue 中使用,同时兼容不支持 WebP 的浏览器:
<template><!-- 优先加载WebP,不支持则加载JPG --><picture><source srcset="/banner.webp" type="image/webp"><img src="/banner.jpg" alt="首页banner" class="banner"></picture></template>

3. 首屏外图片懒加载(延迟加载,减少首屏压力)

  • 原理:首屏外的图片(如下方的商品列表),等用户滚动到可视区域再加载;
  • 实现(用 vue-lazyload):
  1. 安装插件:
npm install vue-lazyload
  1. 在 main.js 中配置:
import { createApp } from 'vue'import App from './App.vue'import VueLazyload from 'vue-lazyload'const app = createApp(App)// 配置懒加载:加载中显示占位图app.use(VueLazyload, {loading: '/loading.gif', // 加载中占位图(建议小于1KB)error: '/error.png' // 加载失败占位图})app.mount('#app')
  1. 在组件中使用:
<template><!-- 用v-lazy替代src --><img v-lazy="item.imgUrl" alt="商品图片" class="product-img" v-for="item in productList" :key="item.id"></template>

效果对比:

指标

优化前

优化后

提升

首屏图片体积

2.3MB

1.1MB

52%

首屏加载时间

2.8s

2.0s

28.6%

避坑提示:

  • 首屏图片不要懒加载,否则会导致首屏空白;
  • WebP 格式在 IE 浏览器不支持,需用 <picture> 标签做兼容。
方案 4:打包优化(最后一步,再挤 10% 体积)

前面 3 个方案解决了核心问题,最后通过打包优化,进一步压缩体积。

1. 拆分公共代码(避免重复打包)

  • 原理:Vue、lodash 等第三方库,会被多个组件引用,拆分后只打包一次,后续组件复用;
  • 实现(Vite 配置):
// vite.config.jsexport default defineConfig({build: {rollupOptions: {output: {// 手动拆分公共代码manualChunks: {vue: ['vue'], // Vue相关代码拆成一个chunklodash: ['lodash'], // lodash拆成一个chunkelement: ['element-plus'] // Element Plus拆成一个chunk}}}}})

2. JS/CSS 压缩(默认开启,无需额外配置)

  • Vite 默认使用 Terser 压缩 JS,CSSNano 压缩 CSS,无需手动配置;
  • 若需加强压缩(如去掉 console.log),可在 vite.config.js 中配置:
export default defineConfig({build: {terserOptions: {compress: {drop_console: true, // 打包时去掉所有console.logdrop_debugger: true // 去掉debugger}}}})

效果对比:

指标

优化前

优化后

提升

总打包体积

2.5MB

1.0MB

60%

首屏加载时间

2.0s

1.5s

25%

http://www.xdnf.cn/news/19156.html

相关文章:

  • 阿里云百炼智能体连接云数据库实践(DMS MCP)
  • AI-调查研究-64-机器人 从零构建机械臂:电机、减速器、传感器与控制系统全剖析
  • 深入解析Qt节点编辑器框架:交互逻辑与样式系统(二)
  • 如何使用 Vector 连接 Easysearch
  • cloudflare-ddns
  • nacos登录认证
  • 2026届大数据毕业设计选题推荐-基于Python的出行路线规划与推荐系统 爬虫数据可视化分析
  • 使用TensorFlow Lite Mirco 跑mirco_speech语音识别yes/no
  • Blender中旋转与翻转纹理的实用方法教学
  • Speculation Rules API
  • 华为HCIP数通学习与认证解析!
  • 从零开始的云计算生活——第五十四天,悬梁刺股,kubernetes模块之组件与网络
  • rapid_table v3.0.0发布了
  • MySQL数据库精研之旅第十四期:索引的 “潜规则”(上)
  • 新手向:Python实现数据可视化图表生成
  • 《R for Data Science (2e)》免费中文翻译 (第6章) --- scripts and projects
  • MySQL-内置函数
  • 【C++详解】C++11(一) 列表初始化、右值引⽤和移动语义
  • 2025五天申请邓白氏编码成功
  • 第八篇 永磁同步电机控制-MTPA、MTPV
  • 计算机网络:数据库(sqlite3)
  • 4.x版本的ant-table+sortablejs实现拖拽排序
  • 快速入门Vue3——语法初识
  • 如何给我们直接创建的类加上索引?和len方法?
  • 数字化生产管理系统 (MES)
  • WINTRUST!_ExplodeMessage的作用是赋值psIndirectData
  • Docker 是什么?
  • python自动化测试工具selenium使用指南
  • 在 Ubuntu 24.04 上安装二进制文件(逐步指南)
  • 模型汇总-数学建模