一、前言
最近接手了一个老项目,首屏加载时间高达 3 秒多,用户体验极差。经过一周的优化,成功将 LCP(最大内容绘制)降到了 0.5s 以内。本文将分享整个优化过程中的实战经验,希望能给正在经历类似问题的你一些启发。
二、问题定位:先找到瓶颈
工欲善其事,必先利其器。 优化前先用 Chrome DevTools 的 Lighthouse 和 Performance 面板分析:
Copy
// 在控制台快速查看关键指标
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`LCP: ${entry.startTime}`);
}
}).observe({ entryTypes: ['largest-contentful-paint'] });
我遇到的问题:
- JS bundle 体积过大(1.8MB)
- 图片资源未压缩
- 没有代码分割,首屏加载了全量代码
三、优化方案实战
3.1 路由懒加载 + 组件异步加载
Copy
// ❌ 优化前:全部打包到一个文件
import Home from './views/Home.vue';
import About from './views/About.vue';
// ✅ 优化后:按需加载
const Home = () => import(/* webpackChunkName: "home" */ './views/Home.vue');
const About = () => import(/* webpackChunkName: "about" */ './views/About.vue');
效果: 首屏 JS 从 1.8MB 降到 320KB
3.2 图片优化三部曲
<!-- 1. 使用 WebP 格式 -->
<picture>
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="描述" loading="lazy">
</picture>
// 2. 实现图片懒加载指令(Vue3)
const vLazy = {
mounted(el, binding) {
const observer = new IntersectionObserver(([{ isIntersecting }]) => {
if (isIntersecting) {
el.src = binding.value;
observer.unobserve(el);
}
});
observer.observe(el);
}
};
3.3 Tree Shaking 深度配置
// webpack.config.js
module.exports = {
optimization: {
usedExports: true, // 标记未使用代码
sideEffects: false, // 无副作用,放心删除
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
};
3.4 预加载关键资源
<!-- 预加载首屏字体 -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
<!-- DNS 预解析 -->
<link rel="dns-prefetch" href="//api.example.com">
四、性能监控与持续优化
优化不是一次性的,需要建立长效监控:
// 上报性能指标到监控平台
const reportPerformance = () => {
const metrics = {
fcp: performance.getEntriesByName('first-contentful-paint')[0]?.startTime,
lcp: performance.getEntriesByType('largest-contentful-paint').pop()?.startTime,
cls: performance.getEntriesByType('layout-shift')
.reduce((sum, entry) => sum + entry.value, 0)
};
navigator.sendBeacon('/api/perf', JSON.stringify(metrics));
};
window.addEventListener('load', reportPerformance);
五、优化成果对比
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| FCP | 1.2s | 0.3s | 75% |
| LCP | 3.1s | 0.5s | 84% |
| JS 体积 | 1.8MB | 320KB | 82% |
| 可交互时间 | 4.5s | 1.2s | 73% |
六、总结
性能优化是一个系统工程,核心思路是:减少资源体积、延迟非关键加载、缓存重复请求。记住,先测量再优化,避免过早优化带来的复杂度。
💡 小提示: 可以使用
webpack-bundle-analyzer可视化分析打包结果,找出体积大户。