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

  2. 在 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)

    }),

    ],

    })

  3. 在组件中直接使用,无需手动 import:

    <template>

    <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> <picture> <source srcset="/banner.webp" type="image/webp"> </picture> </template>

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

  • 原理:首屏外的图片(如下方的商品列表),等用户滚动到可视区域再加载;
  • 实现(用 vue-lazyload):
  1. 安装插件:

    npm install vue-lazyload

  2. 在 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')

  3. 在组件中使用:

    <template> 商品图片 </template>

效果对比:

|--------|-------|-------|-------|
| 指标 | 优化前 | 优化后 | 提升 |
| 首屏图片体积 | 2.3MB | 1.1MB | 52% |
| 首屏加载时间 | 2.8s | 2.0s | 28.6% |

避坑提示:

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

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

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

  • 原理:Vue、lodash 等第三方库,会被多个组件引用,拆分后只打包一次,后续组件复用;
  • 实现(Vite 配置):

    // vite.config.js

    export default defineConfig({

    build: {

    rollupOptions: {

    output: {

    // 手动拆分公共代码

    manualChunks: {

    vue: ['vue'], // Vue相关代码拆成一个chunk

    lodash: ['lodash'], // lodash拆成一个chunk

    element: ['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.log

    drop_debugger: true // 去掉debugger

    }

    }

    }

    })

效果对比:

|--------|-------|-------|-----|
| 指标 | 优化前 | 优化后 | 提升 |
| 总打包体积 | 2.5MB | 1.0MB | 60% |
| 首屏加载时间 | 2.0s | 1.5s | 25% |

相关推荐
唐某人丶1 分钟前
教你如何用 JS 实现 Agent 系统(3)—— 借鉴 Cursor 的设计模式实现深度搜索
前端·人工智能·aigc
看到我请叫我铁锤6 分钟前
vue3使用leaflet的时候高亮显示省市区
前端·javascript·vue.js
南囝coding15 分钟前
Vercel 发布 AI Gateway 神器!可一键访问数百个模型,助力零门槛开发 AI 应用
前端·后端
AI大模型22 分钟前
前端学 AI 不用愁!手把手教你用 LangGraph 实现 ReAct 智能体(附完整流程 + 代码)
前端·llm·agent
小红38 分钟前
网络通信基石:从IP地址到子网划分的完整指南
前端·网络协议
一枚前端小能手43 分钟前
🔥 前端储存这点事 - 5个存储方案让你的数据管理更优雅
前端·javascript
willlzq1 小时前
深入探索Swift的Subscript机制和最佳实践
前端
RockerLau1 小时前
micro-zoe子应用路由路径污染问题
前端
代码代码快快显灵1 小时前
Axios的基本知识点以及vue的开发工程(基于大事件)详细解释
前端·javascript·vue.js
文心快码BaiduComate1 小时前
再获殊荣!文心快码荣膺2025年度优秀软件产品!
前端·后端·代码规范