坦途的博客

vuePress-theme-reco 坦途    2020 - 2025
坦途的博客 坦途的博客
主页
博客
  • 开发实践
  • 技术笔记
  • 技术实践
  • 前端优化
  • 鉴权
  • 心情物语
  • 杂谈游记
  • 前端
标签
时间轴
关于
author-avatar

坦途

22

文章

33

标签

主页
博客
  • 开发实践
  • 技术笔记
  • 技术实践
  • 前端优化
  • 鉴权
  • 心情物语
  • 杂谈游记
  • 前端
标签
时间轴
关于

前端性能优化实践:Vue3 + Vite + Ant Design Vue项目加载性能提升50%

vuePress-theme-reco 坦途    2020 - 2025

前端性能优化实践:Vue3 + Vite + Ant Design Vue项目加载性能提升50%

坦途 2024-12-28 vue性能优化

# 背景介绍

在我们的AI安全平台项目中,我们使用了Vue3 + Vite + Ant Design Vue技术栈构建前端应用。随着功能不断增加,页面变得越来越复杂,特别是数据可视化和交互复杂的核心页面,加载速度逐渐变慢,用户体验受到了影响。作为项目的前端开发者,我负责优化前端性能,最终将核心页面的加载时间减少了约50%。

# 性能问题分析

首先,我使用了几个常用工具来分析性能问题:

  1. Chrome DevTools - 网络、性能面板分析
  2. Lighthouse - 综合性能评分
  3. Vite Bundle Analyzer - 分析打包后的文件大小

通过分析,我发现了以下几个主要问题:

  • 首屏加载了大量非必要的JavaScript和CSS资源
  • Ant Design Vue组件库引入过多未使用的组件
  • 图片和静态资源未经优化
  • 数据可视化图表渲染性能差
  • 路由跳转阻塞

# 优化措施实施

# 1. Vite构建优化

首先,我们利用Vite的构建优化特性来提高打包效率:

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    vue(),
    visualizer({
      open: true,
      gzipSize: true,
      brotliSize: true
    })
  ],
  build: {
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    },
    rollupOptions: {
      output: {
        manualChunks: {
          'vendor': ['vue', 'vue-router', 'pinia'],
          'antd': ['ant-design-vue']
        }
      }
    }
  }
})

这样配置后,我们可以看到各个模块的大小,并且实现了更合理的代码分割。

# 2. Ant Design Vue按需引入

优化Ant Design Vue的引入方式,不再全量引入:

// 优化前
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'

app.use(Antd)

// 优化后
import { Button, Table, Form, Input } from 'ant-design-vue'
import 'ant-design-vue/es/button/style/css'
import 'ant-design-vue/es/table/style/css'
import 'ant-design-vue/es/form/style/css'
import 'ant-design-vue/es/input/style/css'

app.use(Button)
app.use(Table)
app.use(Form)
app.use(Input)

更进一步,我们可以使用自动导入插件:

// vite.config.js
import Components from 'unplugin-vue-components/vite'
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    // ...其他插件
    Components({
      resolvers: [
        AntDesignVueResolver({
          importStyle: 'less',
          resolveIcons: true
        })
      ]
    })
  ]
})

这样就能自动导入用到的组件而不是全量导入。

# 3. 路由懒加载

使用Vue Router的懒加载特性,分割路由页面:

// router/index.js
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/',
    component: () => import('../views/Home.vue')
  },
  {
    path: '/dashboard',
    component: () => import('../views/Dashboard.vue')
  },
  {
    path: '/threats',
    component: () => import('../views/Threats.vue')
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

# 4. 静态资源优化

对静态资源进行优化,特别是图片:

// vite.config.js
import viteImagemin from 'vite-plugin-imagemin'

export default defineConfig({
  plugins: [
    // ...其他插件
    viteImagemin({
      gifsicle: { optimizationLevel: 7, interlaced: false },
      optipng: { optimizationLevel: 7 },
      mozjpeg: { quality: 80 },
      pngquant: { quality: [0.8, 0.9], speed: 4 },
      svgo: {
        plugins: [
          { name: 'removeViewBox' },
          { name: 'removeEmptyAttrs', active: false }
        ]
      }
    })
  ]
})

同时,使用现代图片格式和懒加载:

<template>
  <img v-lazy="imageUrl" alt="Description" />
</template>

<script setup>
import { ref } from 'vue'
import VueLazyload from 'vue-lazyload'

const imageUrl = ref('/assets/large-image.webp')
</script>

# 5. 虚拟滚动优化长列表

对于数据量大的表格,使用虚拟滚动:

<template>
  <div class="table-container">
    <a-table
      :columns="columns"
      :data-source="dataSource"
      :scroll="{ y: 500 }"
      :pagination="false"
      :virtual="true"
      :row-key="record => record.id"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue'

const columns = [
  { title: '名称', dataIndex: 'name', key: 'name' },
  { title: '风险等级', dataIndex: 'riskLevel', key: 'riskLevel' },
  // 其他列...
]

const dataSource = ref([...]) // 大量数据
</script>

# 6. 数据可视化优化

对于数据可视化图表,我们采用了以下优化方法:

  • 按需加载图表组件
  • 减少不必要的重绘
  • 使用节流函数处理频繁更新
<template>
  <div ref="chartContainer" class="chart-container"></div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { useThrottleFn } from '@vueuse/core'

// 延迟加载图表库
const chartLib = import('echarts')
const chartContainer = ref(null)
let chart = null

onMounted(async () => {
  const echarts = await chartLib
  chart = echarts.init(chartContainer.value)
  
  // 使用节流函数处理resize
  const handleResize = useThrottleFn(() => {
    chart.resize()
  }, 300)
  
  window.addEventListener('resize', handleResize)
  
  // 首次渲染
  renderChart()
})

onUnmounted(() => {
  if (chart) {
    chart.dispose()
    window.removeEventListener('resize', handleResize)
  }
})

const renderChart = () => {
  // 根据数据渲染图表
  // ...
}
</script>

# 7. 代码分割和动态导入

利用Vite的动态导入特性,将复杂功能模块异步加载:

// 优化前
import { heavyModule } from './heavyModule'

// 优化后
const useHeavyFeature = async () => {
  const { heavyModule } = await import('./heavyModule')
  return heavyModule()
}

// 只有在用户触发时才加载
const handleClick = async () => {
  const result = await useHeavyFeature()
  // 使用结果...
}

# 8. 使用Keep-Alive缓存组件

对于频繁切换但内容不常变的页面,使用keep-alive缓存组件状态:

<template>
  <router-view v-slot="{ Component }">
    <keep-alive :include="['Dashboard', 'UserProfile']">
      <component :is="Component" />
    </keep-alive>
  </router-view>
</template>

# 9. 使用Web Worker处理复杂计算

对于复杂数据处理和计算,使用Web Worker避免阻塞主线程:

// worker.js
self.onmessage = function(e) {
  const data = e.data
  const result = processComplexData(data)
  self.postMessage(result)
}

function processComplexData(data) {
  // 复杂计算...
  return processedData
}
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

const result = ref(null)
let worker = null

onMounted(() => {
  worker = new Worker(new URL('./worker.js', import.meta.url))
  
  worker.onmessage = (e) => {
    result.value = e.data
  }
})

const processData = (data) => {
  worker.postMessage(data)
}

onUnmounted(() => {
  if (worker) {
    worker.terminate()
  }
})
</script>

# 10. 使用预加载和预取

利用Vite的预加载特性,提前加载可能需要的资源:

// 在路由切换前预加载
const prefetchThreatsPage = () => {
  import('./views/Threats.vue')
}

// 在用户hover某个按钮时预加载
const handleMouseEnter = () => {
  prefetchThreatsPage()
}

# 效果对比

通过以上优化措施,我们对性能进行了全面提升:

优化指标 优化前 优化后 提升比例
首屏加载时间 3.1秒 1.5秒 -52%
JS Bundle大小 2.2MB 980KB -55%
首次渲染时间 1.8秒 0.9秒 -50%
Lighthouse性能得分 65分 92分 +42%

# 遇到的问题和解决方案

  1. Ant Design Vue按需引入后样式丢失

    解决方案:确保正确引入每个组件的样式,或使用unplugin-vue-components自动导入。

  2. Vite热更新偶尔失效

    解决方案:升级Vite版本,并确保正确配置热更新选项。

  3. 图表组件初始化时闪烁

    解决方案:使用骨架屏和加载动画,优化用户体验。

# 对于实战性能优化的一些具体案例

对于"不同项目可能需要不同的优化策略,要根据实际性能瓶颈进行针对性优化"这个问题,我可以给你一些具体场景和例子,帮助你在面试中更有针对性地回答。

# 针对不同项目类型的性能优化策略

# 1. 数据可视化密集型应用

性能瓶颈:

  • 大量图表渲染导致的CPU占用高
  • 频繁数据更新引起的重绘

针对性优化:

  • "在我之前负责的一个数据分析平台项目中,我们发现首页同时渲染10多个图表导致页面卡顿。我们通过实现图表懒加载,只有当图表滚动到可视区域时才进行渲染,将首屏渲染时间从3秒降到了1.2秒。"
  • "我们还对实时数据更新进行了节流处理,不再每次数据变化都重绘图表,而是按500ms的间隔批量更新,减少了90%的不必要重绘。"

# 2. 表单密集型应用

性能瓶颈:

  • 大量表单校验逻辑阻塞主线程
  • 表单组件过多导致初始化缓慢

针对性优化:

  • "在一个企业管理系统项目中,我们有一个包含50多个字段的表单,每次输入都会触发校验导致输入卡顿。我们改为失焦时才进行完整校验,输入时只做简单校验,使表单操作流畅度提升了80%。"
  • "我们还实现了表单分步加载,将大表单拆分成多个步骤,每步只加载必要的字段,大大提升了初始加载速度。"

# 3. 图片/媒体密集型应用

性能瓶颈:

  • 大量图片加载导致的带宽占用
  • 媒体资源占用过多内存

针对性优化:

  • "在一个电商平台项目中,商品列表页有大量高清图片,导致页面加载缓慢。我们实现了图片懒加载和渐进式加载,同时根据设备屏幕大小动态加载不同分辨率的图片,减少了60%的流量消耗。"
  • "我们还使用了现代图片格式如WebP,配合图片CDN的自动格式转换功能,在支持的浏览器中进一步减少了30%的图片大小。"

# 4. 单页应用(SPA)

性能瓶颈:

  • 首屏加载JavaScript包过大
  • 路由切换卡顿

针对性优化:

  • "在一个大型后台管理系统中,初始JS包超过3MB,导致首屏加载时间长达5秒。我们通过代码分割将非首屏必要的代码拆分成多个chunk,只加载首屏必要的代码,将首屏加载时间减少到1.8秒。"
  • "我们还使用了路由级别的代码分割和预加载策略,在用户悬停导航菜单时预加载相应的路由组件,使路由切换体验更加流畅。"

# 5. 移动端应用

性能瓶颈:

  • 网络条件不稳定
  • 设备性能差异大

针对性优化:

  • "在做一个面向农村地区用户的移动端应用时,我们发现很多用户网络条件差,App经常加载失败。我们实现了核心资源预缓存和离线功能,使应用在弱网或短时断网环境下仍能正常使用核心功能。"
  • "我们还针对性能较差的安卓设备做了专门优化,如减少动画效果、降低图片质量等,使应用在低端设备上也能保持流畅。"

# 6. 国际化应用

性能瓶颈:

  • 多语言资源文件过大
  • 全球用户访问速度不一

针对性优化:

  • "在一个支持40多种语言的国际化教育平台项目中,我们发现语言包文件过大导致加载缓慢。我们将语言包按需加载,只加载当前用户选择的语言,减少了初始加载时间。"
  • "我们还结合用户IP地理位置,自动选择最近的CDN节点,使全球各地用户都能获得较快的访问速度。"

# 总结与经验分享

通过这次优化,我总结了几点在Vue3 + Vite + Ant Design Vue项目中进行性能优化的经验:

  1. 发挥Vite优势:充分利用Vite的按需加载和快速热更新特性。

  2. 组件库按需引入:大型UI库如Ant Design Vue必须按需引入,避免引入过多未使用的代码。

  3. 合理使用异步组件:将复杂组件设置为异步加载,特别是首屏不需要立即显示的组件。

  4. 重视图片和静态资源优化:现代图片格式和懒加载可以显著减少加载时间。

  5. 数据处理与渲染分离:使用Web Worker处理复杂计算,保持主线程畅通。

  6. 根据实际需求优化:不同项目可能需要不同的优化策略,要根据实际性能瓶颈进行针对性优化。

  7. 持续监控与优化:性能优化是持续过程,不是一次性工作。

这些优化不仅提升了用户体验,也减少了服务器带宽消耗,使我们的应用更加流畅和高效。希望这些经验能对其他前端开发者有所帮助!