Astro 性能优化深度解析
本文将深入探讨 Astro 应用的性能优化策略,从构建时优化到运行时性能调优。
构建时优化
1. 静态生成优化
// astro.config.ts
import { defineConfig } from 'astro/config';
export default defineConfig({
output: 'static', // 静态生成模式
build: {
inlineStylesheets: 'auto', // 自动内联小CSS文件
split: true, // 启用代码分割
},
vite: {
build: {
rollupOptions: {
output: {
manualChunks: {
// 手动分割第三方库
vendor: ['react', 'react-dom'],
utils: ['lodash', 'date-fns']
}
}
}
}
}
});2. 图片优化策略
---
// 使用 Astro 的图片优化
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
<!-- 响应式图片 -->
<Image
src={heroImage}
alt="英雄图片"
width={800}
height={400}
format="webp"
quality={80}
loading="lazy"
sizes="(max-width: 768px) 100vw, 800px"
/>
<!-- 不同尺寸的图片 -->
<picture>
<source
media="(max-width: 768px)"
srcset={`
${heroImage}?w=400&f=webp 400w,
${heroImage}?w=600&f=webp 600w
`}
/>
<source
srcset={`
${heroImage}?w=800&f=webp 800w,
${heroImage}?w=1200&f=webp 1200w
`}
/>
<Image
src={heroImage}
alt="英雄图片"
width={800}
height={400}
loading="lazy"
/>
</picture>3. CSS 优化
---
// 组件级 CSS 优化
---
<div class="optimized-component">
<h2>优化的组件</h2>
<p>内容文本</p>
</div>
<style>
/* 使用 CSS 自定义属性减少重复 */
:root {
--primary-color: #007acc;
--border-radius: 8px;
--spacing-unit: 1rem;
}
.optimized-component {
/* 使用 contain 属性优化渲染 */
contain: layout style;
/* 使用 transform 而不是改变 position */
transform: translateZ(0); /* 创建新的层叠上下文 */
/* 优化字体渲染 */
font-display: swap;
text-rendering: optimizeLegibility;
}
/* 使用 @layer 管理 CSS 优先级 */
@layer base, components, utilities;
@layer base {
body {
font-family: system-ui, sans-serif;
}
}
@layer components {
.optimized-component {
background: var(--primary-color);
border-radius: var(--border-radius);
padding: var(--spacing-unit);
}
}
</style>运行时性能优化
1. 岛屿架构优化
---
// 智能的客户端指令使用
import HeavyComponent from '../components/HeavyComponent.jsx';
import LightComponent from '../components/LightComponent.astro';
---
<!-- 立即需要交互的组件 -->
<HeavyComponent client:load />
<!-- 页面空闲时加载 -->
<HeavyComponent client:idle />
<!-- 进入视口时加载 -->
<HeavyComponent client:visible />
<!-- 媒体查询匹配时加载 -->
<HeavyComponent client:media="(max-width: 768px)" />
<!-- 仅在特定条件下加载 -->
{shouldLoadInteractive && (
<HeavyComponent client:load />
)}
<!-- 静态组件,无需 JavaScript -->
<LightComponent />2. 代码分割和懒加载
// utils/lazyLoad.ts
export async function lazyLoadComponent(componentName: string) {
const modules = {
'Chart': () => import('../components/Chart.jsx'),
'DataTable': () => import('../components/DataTable.jsx'),
'VideoPlayer': () => import('../components/VideoPlayer.jsx')
};
const moduleLoader = modules[componentName];
if (!moduleLoader) {
throw new Error(`Component ${componentName} not found`);
}
return await moduleLoader();
}---
// 在页面中使用懒加载
const shouldShowChart = Astro.url.searchParams.has('chart');
---
{shouldShowChart && (
<div id="chart-container" data-component="Chart">
<div class="loading-placeholder">
加载图表中...
</div>
</div>
)}
<script>
// 客户端懒加载逻辑
document.addEventListener('DOMContentLoaded', async () => {
const containers = document.querySelectorAll('[data-component]');
const observer = new IntersectionObserver(async (entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
const container = entry.target;
const componentName = container.getAttribute('data-component');
try {
const { default: Component } = await import(`../components/${componentName}.jsx`);
// 渲染组件逻辑
observer.unobserve(container);
} catch (error) {
console.error(`Failed to load component ${componentName}:`, error);
}
}
}
});
containers.forEach(container => observer.observe(container));
});
</script>3. 缓存策略
// middleware/cache.ts
import type { MiddlewareHandler } from 'astro';
export const cacheMiddleware: MiddlewareHandler = async (context, next) => {
const response = await next();
// 静态资源长期缓存
if (context.url.pathname.match(/\.(js|css|png|jpg|jpeg|gif|svg|woff2?)$/)) {
response.headers.set('Cache-Control', 'public, max-age=31536000, immutable');
}
// HTML 页面短期缓存
else if (context.url.pathname.endsWith('.html') || !context.url.pathname.includes('.')) {
response.headers.set('Cache-Control', 'public, max-age=3600, must-revalidate');
}
// API 响应缓存
else if (context.url.pathname.startsWith('/api/')) {
response.headers.set('Cache-Control', 'public, max-age=300');
}
return response;
};性能监控和分析
1. Core Web Vitals 监控
// utils/performance.ts
interface PerformanceMetrics {
FCP: number; // First Contentful Paint
LCP: number; // Largest Contentful Paint
FID: number; // First Input Delay
CLS: number; // Cumulative Layout Shift
}
export class PerformanceMonitor {
private metrics: Partial<PerformanceMetrics> = {};
constructor() {
this.observeMetrics();
}
private observeMetrics() {
// 观察 LCP
new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
const lastEntry = entries[entries.length - 1];
this.metrics.LCP = lastEntry.startTime;
}).observe({ entryTypes: ['largest-contentful-paint'] });
// 观察 FID
new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
entries.forEach((entry) => {
this.metrics.FID = entry.processingStart - entry.startTime;
});
}).observe({ entryTypes: ['first-input'] });
// 观察 CLS
let clsValue = 0;
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += entry.value;
}
}
this.metrics.CLS = clsValue;
}).observe({ entryTypes: ['layout-shift'] });
}
public reportMetrics() {
// 发送到分析服务
fetch('/api/analytics/performance', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: window.location.href,
metrics: this.metrics,
timestamp: Date.now()
})
});
}
}2. 资源加载优化
---
// 预加载关键资源
---
<head>
<!-- 预加载关键字体 -->
<link
rel="preload"
href="/fonts/inter-var.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<!-- 预连接到外部域名 -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://api.example.com" />
<!-- DNS 预解析 -->
<link rel="dns-prefetch" href="https://cdn.example.com" />
<!-- 预加载关键 CSS -->
<link rel="preload" href="/styles/critical.css" as="style" />
</head>3. 构建分析工具
// scripts/analyze-bundle.ts
import { build } from 'vite';
import { visualizer } from 'rollup-plugin-visualizer';
async function analyzeBuild() {
await build({
plugins: [
visualizer({
filename: 'dist/bundle-analysis.html',
open: true,
gzipSize: true,
brotliSize: true
})
],
build: {
rollupOptions: {
output: {
manualChunks(id) {
// 分析和优化代码分割
if (id.includes('node_modules')) {
if (id.includes('react')) return 'react-vendor';
if (id.includes('lodash')) return 'utils-vendor';
return 'vendor';
}
}
}
}
}
});
}
analyzeBuild();性能优化检查清单
✅ 构建时优化
- 启用静态生成模式
- 配置代码分割
- 优化图片格式和尺寸
- 压缩和内联关键 CSS
- 移除未使用的代码
✅ 运行时优化
- 合理使用客户端指令
- 实施懒加载策略
- 优化字体加载
- 减少布局偏移
- 实施资源预加载
✅ 监控和分析
- 设置 Core Web Vitals 监控
- 配置性能预算
- 定期进行性能审计
- 分析构建产物大小
- 监控实际用户性能数据
通过系统性地应用这些优化策略,你的 Astro 应用将能够提供卓越的用户体验和优异的性能表现。