博客部署和性能优化指南

2024-04-05·无心文字

博客部署和性能优化指南

本指南将帮你把 Taco 部署到生产环境,并进行性能优化,让你的博客访问速度飞快。

🚀 部署方案选择

1. Vercel 部署(推荐)

Vercel 是 Next.js 的官方部署平台,提供最佳的开发体验。

优势

  • ✅ 零配置部署
  • ✅ 自动构建和部署
  • ✅ 全球 CDN 分发
  • ✅ 支持自定义域名
  • ✅ 免费额度充足

部署步骤

  1. 连接 GitHub 仓库

    # 推送代码到 GitHub
    git add .
    git commit -m "准备部署"
    git push origin main
    
  2. Vercel 控制台配置

    • 访问 vercel.com
    • 点击 "New Project"
    • 选择你的 GitHub 仓库
    • Framework Preset 选择 "Next.js"
  3. 环境变量配置

    # .env.local(生产环境)
    NEXT_PUBLIC_SITE_URL=https://yourdomain.com
    NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX  # Google Analytics(可选)
    
  4. 自动部署

    # 每次推送都会自动重新部署
    git push origin main
    

2. Netlify 部署

另一个优秀的静态站点托管平台。

配置文件

创建 netlify.toml

[build]
  command = "pnpm build"
  publish = ".next"

[build.environment]
  NODE_VERSION = "18"

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

3. 自建服务器部署

使用 Docker 进行容器化部署。

Dockerfile

FROM node:18-alpine AS deps
WORKDIR /app
COPY package*.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile

FROM node:18-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm install -g pnpm && pnpm build

FROM node:18-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

EXPOSE 3000
ENV PORT 3000

CMD ["node", "server.js"]

docker-compose.yml

version: '3.8'
services:
  blog:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - NEXT_PUBLIC_SITE_URL=https://yourdomain.com
    restart: unless-stopped

⚡ 性能优化

1. 图片优化

Next.js Image 组件

确保使用 Next.js 的 Image 组件:

import Image from 'next/image'

// 自动优化的图片组件
<Image
  src="/hero-image.jpg"
  alt="Hero Image"
  width={1200}
  height={600}
  priority
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>

图片格式优化

next.config.js 中配置:

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    formats: ['image/webp', 'image/avif'],
    domains: [
      'images.unsplash.com',
      'your-cdn-domain.com'
    ],
    minimumCacheTTL: 60 * 60 * 24 * 30, // 30天缓存
  }
}

图片懒加载

<Image
  src="/large-image.jpg"
  alt="Large Image"
  width={800}
  height={600}
  loading="lazy"  // 懒加载
  placeholder="blur"  // 模糊占位符
  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
/>

2. 代码优化

代码分割

// 动态导入组件
import { lazy, Suspense } from 'react'

const HeavyComponent = lazy(() => import('./HeavyComponent'))

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyComponent />
    </Suspense>
  )
}

Bundle 分析

# 安装分析工具
npm install --save-dev @next/bundle-analyzer

# 分析构建结果
ANALYZE=true pnpm build

next.config.js 中配置:

const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
})

module.exports = withBundleAnalyzer({
  // 其他配置
})

3. 缓存策略

静态资源缓存

next.config.js 中设置:

const nextConfig = {
  async headers() {
    return [
      {
        source: '/images/:path*',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=31536000, immutable'
          }
        ]
      },
      {
        source: '/(.*)',
        headers: [
          {
            key: 'X-Frame-Options',
            value: 'DENY'
          },
          {
            key: 'X-Content-Type-Options',
            value: 'nosniff'
          }
        ]
      }
    ]
  }
}

ISR(增量静态生成)

// 为文章页面启用 ISR
export async function getStaticProps({ params }) {
  const post = await getPost(params.slug)
  
  return {
    props: { post },
    revalidate: 3600, // 每小时重新生成
  }
}

4. 字体优化

预加载关键字体

import { Inter } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  preload: true,
})

export default function RootLayout({ children }) {
  return (
    <html lang="zh-CN" className={inter.className}>
      <body>{children}</body>
    </html>
  )
}

字体回退策略

/* 在 globals.css 中设置字体回退 */
.font-main {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  font-display: swap;
}

📊 性能监控

1. Core Web Vitals

确保你的博客通过 Core Web Vitals 指标:

  • LCP (Largest Contentful Paint) < 2.5s
  • FID (First Input Delay) < 100ms
  • CLS (Cumulative Layout Shift) < 0.1

2. 性能监控工具

Lighthouse CI

# .github/workflows/lighthouse.yml
name: Lighthouse CI
on: [push]
jobs:
  lhci:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
      - run: npm install && npm run build
      - run: npm install -g @lhci/cli@0.11.x
      - run: lhci autorun

Real User Monitoring

// 添加到 _app.js 或 layout.js
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals'

function sendToAnalytics(metric) {
  // 发送到分析服务
  gtag('event', metric.name, {
    value: Math.round(metric.value),
    metric_id: metric.id,
    metric_value: metric.value,
    metric_delta: metric.delta,
  })
}

// 监控所有重要指标
getCLS(sendToAnalytics)
getFID(sendToAnalytics)
getFCP(sendToAnalytics)
getLCP(sendToAnalytics)
getTTFB(sendToAnalytics)

3. 错误监控

Sentry 集成

npm install @sentry/nextjs
// sentry.client.config.js
import * as Sentry from '@sentry/nextjs'

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 1.0,
})

🔒 安全优化

1. 安全头部

// next.config.js
const securityHeaders = [
  {
    key: 'X-DNS-Prefetch-Control',
    value: 'on'
  },
  {
    key: 'Strict-Transport-Security',
    value: 'max-age=63072000; includeSubDomains; preload'
  },
  {
    key: 'X-XSS-Protection',
    value: '1; mode=block'
  },
  {
    key: 'X-Frame-Options',
    value: 'SAMEORIGIN'
  },
  {
    key: 'Permissions-Policy',
    value: 'camera=(), microphone=(), geolocation=()'
  },
  {
    key: 'X-Content-Type-Options',
    value: 'nosniff'
  },
  {
    key: 'Referrer-Policy',
    value: 'origin-when-cross-origin'
  }
]

const nextConfig = {
  async headers() {
    return [
      {
        source: '/(.*)',
        headers: securityHeaders,
      }
    ]
  }
}

2. Content Security Policy

const ContentSecurityPolicy = `
  default-src 'self';
  script-src 'self' 'unsafe-eval' 'unsafe-inline' *.google-analytics.com;
  child-src *.youtube.com *.google.com *.twitter.com;
  style-src 'self' 'unsafe-inline' *.googleapis.com;
  img-src * blob: data:;
  media-src 'none';
  connect-src *;
  font-src 'self' *.gstatic.com;
`;

const securityHeaders = [
  {
    key: 'Content-Security-Policy',
    value: ContentSecurityPolicy.replace(/\n/g, ''),
  }
]

🌍 SEO 优化

1. 结构化数据

// 在文章页面添加 JSON-LD
const structuredData = {
  '@context': 'https://schema.org',
  '@type': 'BlogPosting',
  headline: post.title,
  image: post.banner?.img,
  author: {
    '@type': 'Person',
    name: 'Your Name'
  },
  publisher: {
    '@type': 'Organization',
    name: 'Your Blog Name',
    logo: {
      '@type': 'ImageObject',
      url: 'https://yourdomain.com/logo.png'
    }
  },
  datePublished: post.date,
  dateModified: post.lastModified || post.date
}

return (
  <script
    type="application/ld+json"
    dangerouslySetInnerHTML={{
      __html: JSON.stringify(structuredData)
    }}
  />
)

2. Sitemap 生成

// app/sitemap.xml/route.js
import { MetadataRoute } from 'next'
import { getAllPosts } from '@/lib/posts'

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const posts = await getAllPosts()
  
  const postEntries: MetadataRoute.Sitemap = posts.map((post) => ({
    url: `${process.env.NEXT_PUBLIC_SITE_URL}/blog/${post.slug}`,
    lastModified: post.lastModified || post.date,
    changeFrequency: 'weekly',
    priority: 0.7,
  }))

  return [
    {
      url: process.env.NEXT_PUBLIC_SITE_URL,
      lastModified: new Date(),
      changeFrequency: 'daily',
      priority: 1,
    },
    ...postEntries,
  ]
}

📈 Analytics 集成

1. Google Analytics 4

// lib/gtag.js
export const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_ID

export const pageview = (url) => {
  window.gtag('config', GA_TRACKING_ID, {
    page_path: url,
  })
}

export const event = ({ action, category, label, value }) => {
  window.gtag('event', action, {
    event_category: category,
    event_label: label,
    value: value,
  })
}

2. 自定义事件追踪

// 追踪文章阅读时间
useEffect(() => {
  const startTime = Date.now()
  
  return () => {
    const readTime = Date.now() - startTime
    event({
      action: 'read_time',
      category: 'engagement',
      label: post.slug,
      value: Math.round(readTime / 1000)
    })
  }
}, [])

✅ 部署检查清单

部署前确保完成以下检查:

基础检查

  • 代码构建无错误
  • 所有页面能正常访问
  • 响应式设计在各设备上正常
  • 图片和资源文件正常加载

性能检查

  • Lighthouse 分数 > 90
  • 首页 LCP < 2.5s
  • 图片已优化(WebP格式)
  • 代码已压缩和分割

SEO检查

  • 每个页面有独特的 title 和 description
  • 添加了 Open Graph 标签
  • 生成了 sitemap.xml
  • 配置了 robots.txt

安全检查

  • 添加了安全头部
  • HTTPS 证书配置
  • 移除了开发调试代码
  • 环境变量正确配置

🎉 部署完成

恭喜!你的 Taco 现在已经部署到生产环境并经过了性能优化。

下一步建议

  1. 定期监控网站性能
  2. 设置错误报警
  3. 备份重要数据
  4. 定期更新依赖

你的博客现在应该能够提供快速、安全、用户友好的访问体验了!🚀