图片等媒体资源优化
图片等媒体资源优化的必要性
现代Web应用大量使用图片、视频等媒体资源,这些资源往往占据页面加载时间的大头。未优化的媒体资源会导致首屏加载缓慢、带宽浪费和用户体验下降。Vite作为新一代前端构建工具,提供了多种开箱即用的优化手段。
Vite内置的图片处理能力
Vite默认支持图片资源的导入,无需额外配置即可在代码中直接引用:
import logo from './assets/logo.png'
function Header() {
return <img src={logo} alt="Logo" />
}
Vite会自动处理这些资源:
- 小于4KB的图片转为base64内联
- 较大的图片生成哈希文件名并复制到输出目录
- 提供图片的public路径解析
图片格式选择与转换
WebP格式的优势
WebP通常比PNG/JPG小25-35%,支持透明度和动画。Vite可以通过插件自动转换:
npm install vite-plugin-webp -D
配置vite.config.js:
import { defineConfig } from 'vite'
import webp from 'vite-plugin-webp'
export default defineConfig({
plugins: [
webp({
quality: 80,
// 只转换大于10KB的图片
filter: (filePath, fileBuffer) => fileBuffer.length > 10240
})
]
})
AVIF格式的进阶优化
AVIF比WebP再小20-30%,但编码时间更长。适合对性能要求极高的场景:
// vite.config.js
import avif from 'vite-plugin-avif'
export default defineConfig({
plugins: [
avif({
quality: 50,
speed: 5 // 1-9,数值越大编码越快但压缩率越低
})
]
})
响应式图片处理
基于视口的动态加载
使用vite-plugin-responsive-loader
生成多尺寸版本:
// vite.config.js
import responsive from 'vite-plugin-responsive-loader'
export default defineConfig({
plugins: [
responsive({
sizes: [320, 640, 1024, 1600],
formats: ['webp', 'original']
})
]
})
组件中使用:
const sources = [
{ srcset: '/assets/hero-320.webp 320w', type: 'image/webp' },
{ srcset: '/assets/hero-640.webp 640w', type: 'image/webp' },
{ srcset: '/assets/hero-1024.webp 1024w', type: 'image/webp' }
]
function HeroImage() {
return (
<picture>
{sources.map((src, i) => (
<source key={i} {...src} />
))}
<img src="/assets/hero-1024.jpg" alt="Hero" />
</picture>
)
}
懒加载实现
原生loading属性
最简单的懒加载方式:
<img src="image.jpg" loading="lazy" alt="Lazy loaded" />
Intersection Observer API
更精细控制的实现:
// lazy.js
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
observer.unobserve(img)
}
})
}, {
rootMargin: '200px'
})
document.querySelectorAll('[data-src]').forEach(img => {
observer.observe(img)
})
组件中使用:
<img data-src="/large-image.jpg" alt="Lazy" class="lazy" />
雪碧图优化
使用vite-plugin-sprite
合并小图标:
npm install vite-plugin-sprite -D
配置示例:
// vite.config.js
import sprite from 'vite-plugin-sprite'
export default defineConfig({
plugins: [
sprite({
// 匹配icons目录下的svg
include: 'src/assets/icons/*.svg',
output: 'public/sprites'
})
]
})
使用生成的雪碧图:
.icon {
background-image: url('/sprites/sprite.svg');
}
.icon-home {
width: 24px;
height: 24px;
background-position: 0 0;
}
视频资源优化策略
视频格式选择
优先使用WebM而非MP4:
<video width="640" height="360" controls>
<source src="video.webm" type="video/webm">
<source src="video.mp4" type="video/mp4">
</video>
视频预加载策略
根据网络条件动态加载:
function loadVideo() {
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection
const video = document.getElementById('hero-video')
if (connection) {
const effectiveType = connection.effectiveType
video.src = effectiveType === '4g' ? 'hd.webm' : 'sd.webm'
} else {
video.src = 'sd.webm'
}
}
媒体资源的CDN加速
配置Vite的base路径指向CDN:
// vite.config.js
export default defineConfig({
base: process.env.NODE_ENV === 'production'
? 'https://cdn.yourdomain.com/assets/'
: '/'
})
结合内容哈希确保缓存有效性:
// vite.config.js
export default defineConfig({
build: {
rollupOptions: {
output: {
assetFileNames: 'assets/[name]-[hash][extname]'
}
}
}
})
媒体资源的按需加载
动态导入大尺寸资源:
function loadHeroImage() {
import('./assets/hero-image.webp').then(module => {
document.getElementById('hero').style.backgroundImage = `url(${module.default})`
})
}
// 在需要时触发
window.addEventListener('scroll', loadHeroImage, { once: true })
缓存策略的最佳实践
配置强缓存和协商缓存:
# Nginx配置示例
location ~* \.(jpg|jpeg|png|gif|ico|webp|svg|mp4|webm)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
对于频繁更新的资源:
location ~* \.(js|css)$ {
expires 7d;
add_header Cache-Control "public, must-revalidate";
}
性能监控与调优
使用Chrome DevTools的Coverage工具分析未使用资源:
// 在控制台直接运行
console.table(performance.getEntriesByType('resource')
.filter(r => r.initiatorType === 'img')
.map(r => ({
name: r.name,
duration: `${r.duration.toFixed(2)}ms`,
size: `${(r.transferSize / 1024).toFixed(2)}KB`
}))
)
实现资源加载监控:
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
console.log(`[${entry.initiatorType}] ${entry.name}:
${entry.duration.toFixed(2)}ms`)
})
})
observer.observe({ entryTypes: ['resource'] })
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:第三方库的优化引入方式
下一篇:现代化构建的配置技巧