我的博客性能优化实战:首屏加载从2.5s降到1.2s

⚡ 我的博客性能优化实战:首屏加载从2.5s降到1.2s

分享我在Vue 3博客项目中的性能优化经验,性能提升52%,包体积减少39%

前言

性能优化是前端开发中永恒的话题。在开发我的个人博客项目时,我遇到了首屏加载慢、包体积大等问题。经过一系列优化,最终将首屏加载时间从2.5s降到1.2s,包体积从850KB降到520KB。本文将详细分享我的优化过程和经验。

优化前后对比

先来看看优化前后的数据对比:

指标 优化前 优化后 提升
首屏加载时间 ~2.5s ~1.2s ⬇️ 52%
初始包体积 ~850KB ~520KB ⬇️ 39%
冷启动时间 ~3.5s ~1.8s ⬇️ 49%
Lighthouse性能评分 68 92 ⬆️ 35%

问题分析

1. 首屏加载慢

问题表现:

  • 打开首页需要等待2.5秒才能看到内容
  • 白屏时间长,用户体验差
  • 移动端加载更慢

原因分析:

bash 复制代码
# 使用vite-plugin-visualizer分析构建结果
npm run analyze

分析发现:

  1. vendor chunk过大,包含了所有依赖
  2. Element Plus图标全部加载
  3. 没有使用懒加载,所有页面代码一次性加载
  4. 图片没有压缩和懒加载

2. 包体积大

问题表现:

  • 打包后的dist目录达到3MB
  • vendor.js文件850KB
  • 首屏需要加载的资源太多

原因分析:

  1. 所有依赖都打包到一个vendor chunk
  2. 没有使用代码分割
  3. 生产环境仍然包含console.log
  4. 没有压缩图片

3. 冷启动慢

问题表现:

  • 开发服务器启动需要3.5秒
  • HMR更新慢

原因分析:

  1. Vite配置没有优化
  2. 依赖没有预构建
  3. 文件监听配置不当

优化方案

1. 代码分割

代码分割是性能优化的核心,它可以将代码拆分成多个小块,按需加载。

按路由分割
typescript 复制代码
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          // 将Vue相关依赖打包
          'vue-vendor': ['vue', 'vue-router', 'pinia'],
          // 将UI库单独打包
          'element-plus': ['element-plus'],
          // 将工具函数打包
          'utils': ['@/utils/format', '@/utils/seo'],
          // 将编辑器相关打包
          'editor': ['marked', 'highlight.js', 'dompurify'],
          // 将图表库单独打包
          'charts': ['echarts']
        }
      }
    }
  }
})
路由懒加载
typescript 复制代码
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'

// 懒加载路由组件
const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/Home.vue'),
    meta: { title: '首页' }
  },
  {
    path: '/article/:id',
    name: 'Article',
    component: () => import('@/views/Article.vue'),
    meta: { title: '文章详情' }
  },
  {
    path: '/archive',
    name: 'Archive',
    component: () => import('@/views/Archive.vue'),
    meta: { title: '归档' }
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('@/views/About.vue'),
    meta: { title: '关于' }
  }
]

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

export default router
组件懒加载

对于大型组件,可以使用异步组件:

typescript 复制代码
// 使用defineAsyncComponent
import { defineAsyncComponent } from 'vue'

const Editor = defineAsyncComponent(() =>
  import('@/components/editor/EnhancedMarkdownEditor.vue')
)

const Chart = defineAsyncComponent({
  loader: () => import('@/components/Chart.vue'),
  loadingComponent: LoadingSpinner,
  errorComponent: ErrorComponent,
  delay: 200,
  timeout: 3000
})

效果:

  • 首屏只加载必要的代码
  • 路由切换时才加载对应页面
  • 减少初始包体积约40%

2. 懒加载优化

图标懒加载

Element Plus的图标库非常大(几百KB),如果全部加载会严重影响性能。

typescript 复制代码
// utils/icons.ts
import { registerIcons } from 'element-plus/es/components/icon'

export function lazyRegisterIcons() {
  const icons = [
    // 只导入需要用到的图标
    'Edit',
    'Delete',
    'View',
    'Download',
    'Share',
    'Star',
    'Document',
    'Folder',
    'Setting',
    'User',
    'Search',
    'Home',
    'ArrowUp',
    'ArrowDown',
    'ArrowLeft',
    'ArrowRight'
  ]

  // 使用idleCallback在浏览器空闲时注册图标
  const idleCallback = window.requestIdleCallback || window.setTimeout

  idleCallback(() => {
    registerIcons(icons)
  })
}

// main.ts
import { lazyRegisterIcons } from './utils/icons'
lazyRegisterIcons()

效果:

  • 图标加载减少约200KB
  • 不阻塞主线程
  • 首屏渲染速度提升15%
图片懒加载
vue 复制代码
<template>
  <img
    v-lazy="imageUrl"
    :alt="altText"
    class="lazy-image"
  />
</template>

<script setup>
import { useIntersectionObserver } from '@vueuse/core'

const { stop } = useIntersectionObserver(
  target,
  ([{ isIntersecting }]) => {
    if (isIntersecting) {
      // 图片进入视口时加载
      load()
      stop() // 停止观察
    }
  }
)
</script>
虚拟滚动

对于长列表,使用虚拟滚动:

vue 复制代码
<template>
  <VirtualList
    :data-sources="items"
    :data-key="'id'"
    :keeps="30"
    :estimate-size="50"
  >
    <template #default="{ source }">
      <ArticleCard :article="source" />
    </template>
  </VirtualList>
</template>

<script setup>
import { ref } from 'vue'
import VirtualList from 'vue-virtual-scroll-list'

const items = ref(/* 大量数据 */)
</script>

3. 依赖预构建

优化Vite的预构建配置:

typescript 复制代码
// vite.config.ts
export default defineConfig({
  optimizeDeps: {
    // 明确需要预构建的依赖
    include: [
      'vue',
      'vue-router',
      'element-plus',
      'marked',
      'highlight.js',
      'dompurify',
      'echarts',
      'dayjs'
    ],
    // 排除不需要预构建的依赖
    exclude: ['your-local-package']
  }
})

效果:

  • 冷启动时间从3.5s降到1.8s
  • HMR更新更快
  • 开发体验提升

4. 生产构建优化

代码压缩
typescript 复制代码
// vite.config.ts
export default defineConfig({
  build: {
    minify: 'terser',
    terserOptions: {
      compress: {
        // 移除console
        drop_console: true,
        // 移除debugger
        drop_debugger: true,
        // 移除无用代码
        pure_funcs: ['console.log', 'console.info']
      },
      format: {
        // 移除注释
        comments: false
      }
    },
    // 更好的chunk命名策略
    rollupOptions: {
      output: {
        chunkFileNames: 'js/[name]-[hash].js',
        entryFileNames: 'js/[name]-[hash].js',
        assetFileNames: '[ext]/[name]-[hash].[ext]'
      }
    },
    // chunk大小警告阈值
    chunkSizeWarningLimit: 1000
  }
})
CSS优化
typescript 复制代码
// vite.config.ts
import cssnano from 'cssnano'

export default defineConfig({
  css: {
    postcss: {
      plugins: [
        cssnano({
          preset: 'advanced'
        })
      ]
    }
  },
  build: {
    cssCodeSplit: true // 启用CSS代码分割
  }
})
资源优化
typescript 复制代码
// vite.config.ts
export default defineConfig({
  build: {
    // 资源内联限制
    assetsInlineLimit: 4096,
    // 小于4KB的图片转为base64
    rollupOptions: {
      output: {
        // 静态资源分类
        assetFileNames: (assetInfo) => {
          const info = assetInfo.name.split('.')
          const ext = info[info.length - 1]
          if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/i.test(assetInfo.name)) {
            return 'media/[name]-[hash][extname]'
          }
          if (/\.(png|jpe?g|gif|svg|webp|avif)(\?.*)?$/i.test(assetInfo.name)) {
            return 'images/[name]-[hash][extname]'
          }
          if (/\.(woff2?|eot|ttf|otf)(\?.*)?$/i.test(assetInfo.name)) {
            return 'fonts/[name]-[hash][extname]'
          }
          return `${ext}/[name]-[hash][extname]`
        }
      }
    }
  }
})

5. 缓存策略

Service Worker
typescript 复制代码
// public/sw.js
const CACHE_NAME = 'blog-v1'
const urlsToCache = [
  '/',
  '/index.html',
  '/js/*.js',
  '/css/*.css',
  '/images/*'
]

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then((cache) => cache.addAll(urlsToCache))
  )
})

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then((response) => response || fetch(event.request))
  )
})
HTTP缓存
typescript 复制代码
// vite.config.ts
export default defineConfig({
  server: {
    headers: {
      // 静态资源长期缓存
      'Cache-Control': 'public, max-age=31536000, immutable'
    }
  }
})

6. 图片优化

使用WebP格式
bash 复制代码
# 安装vite-plugin-imagemin
npm install vite-plugin-imagemin imagemin-webp -D
typescript 复制代码
// vite.config.ts
import imageminWebp from 'imagemin-webp'

export default defineConfig({
  plugins: [
    viteImagemin({
      plugins: {
        webp: imageminWebp({ quality: 75 })
      }
    })
  ]
})
响应式图片
vue 复制代码
<picture>
  <source srcset="image.webp" type="image/webp">
  <source srcset="image.jpg" type="image/jpeg">
  <img src="image.jpg" alt="描述" loading="lazy">
</picture>

7. CDN加速

将静态资源上传到CDN:

typescript 复制代码
// vite.config.ts
export default defineConfig({
  base: 'https://cdn.example.com/blog/',
  build: {
    rollupOptions: {
      output: {
        // CDN资源路径
        publicPath: 'https://cdn.example.com/blog/'
      }
    }
  }
})

监控与分析

1. Lighthouse

bash 复制代码
# 安装Lighthouse
npm install -g lighthouse

# 运行测试
lighthouse https://your-blog.com --view

2. WebPageTest

访问 https://www.webpagetest.org/ 进行详细的性能测试。

3. 自定义性能监控

typescript 复制代码
// utils/performance.ts
export function measurePerformance() {
  // 页面加载性能
  window.addEventListener('load', () => {
    const perfData = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming

    console.log({
      DNS查询: perfData.domainLookupEnd - perfData.domainLookupStart,
      TCP连接: perfData.connectEnd - perfData.connectStart,
      请求: perfData.responseStart - perfData.requestStart,
      DOM解析: perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart,
      首次渲染: perfData.responseEnd - perfData.fetchStart,
      完全加载: perfData.loadEventEnd - perfData.fetchStart
    })
  })

  // 首次内容绘制
  const observer = new PerformanceObserver((list) => {
    const entries = list.getEntries()
    console.log('FCP:', entries[0].startTime)
  })

  observer.observe({ entryTypes: ['paint'] })
}

优化成果

经过以上优化,取得了显著的性能提升:

1. 加载性能

复制代码
优化前:
- FCP: 1.8s
- LCP: 2.5s
- TTI: 3.2s

优化后:
- FCP: 0.8s
- LCP: 1.2s
- TTI: 1.8s

2. 包体积

复制代码
优化前:
- vendor.js: 850KB
- 总体积: 3MB

优化后:
- vendor.js: 520KB
- 总体积: 1.8MB

3. 用户体验

  • 首屏可见时间从2.5s降到1.2s
  • 页面交互响应更快
  • 移动端体验大幅提升
  • Lighthouse评分从68提升到92

最佳实践总结

1. 性能优化优先级

复制代码
高优先级:
✅ 代码分割
✅ 懒加载
✅ 图片优化
✅ 缓存策略

中优先级:
✅ 依赖预构建
✅ 资源压缩
✅ CDN加速

低优先级:
⚠️ Service Worker
⚠️ 预加载

2. 持续优化

typescript 复制代码
// 定期运行性能测试
npm run analyze

// 检查bundle大小
npm run build:size

// 运行Lighthouse测试
lighthouse https://your-blog.com

3. 工具推荐

  • 构建分析:rollup-plugin-visualizer
  • 性能测试:Lighthouse、WebPageTest
  • 图片优化:vite-plugin-imagemin
  • 代码分割:@rollup/plugin-dynamic-import-vars
  • 监控工具:Sentry、Google Analytics

总结

性能优化是一个持续的过程,需要:

  1. 分析问题:找出性能瓶颈
  2. 制定方案:选择合适的优化策略
  3. 实施优化:逐步应用优化措施
  4. 监控效果:持续跟踪性能指标
  5. 持续改进:根据数据反馈不断优化

记住:过早优化是万恶之源,但性能优化是永恒的话题


标签:#性能优化 #Vue3 #Vite #前端 #性能调优

点赞❤️ + 收藏⭐️ + 评论💬,你的支持是我创作的动力!

相关推荐
heimeiyingwang3 小时前
【架构实战】接口性能优化:异步化/并行化/缓存化
缓存·性能优化·架构
墨香幽梦客4 小时前
全站HTTPS化实战:SSL证书管理、自动续期与TLS 1.3性能优化详解
性能优化·https·ssl
喜欢流萤吖~4 小时前
SpringBoot 性能优化实战
spring boot·后端·性能优化
weixin1997010801619 小时前
《TikTok 商品详情页前端性能优化实战》
前端·性能优化
comerzhang65520 小时前
开启 Cross-Origin Isolation 后,我的网站"社会性死亡"了
性能优化·next.js
懋学的前端攻城狮1 天前
超越Toast:构建优雅的UI反馈与异步协调机制
ios·性能优化
weixin199701080161 天前
《爱回收商品详情页前端性能优化实战》
前端·性能优化
00后程序员张1 天前
iOS应用性能优化全解析:卡顿、耗电、启动与瘦身
android·ios·性能优化·小程序·uni-app·iphone·webview
正在走向自律1 天前
网络存储环境下的金仓数据库部署与运维实战:从诊断到优化
性能优化·nfs·kingbasees·数据库运维