Skip to content
第 25 章 前端 ⏱ 15 分钟阅读

第 25 章:部署与进阶 ​

学习目标 ​

  • 掌握 Vercel 部署 Next.js
  • 学会 Docker 部署
  • 性能优化(图片、字体、代码分割)
  • React 18 并发特性实战

一、Vercel 部署(Next.js 首选) ​

bash
npm install -g vercel
vercel login
vercel           # 部署预览环境
vercel --prod    # 部署生产环境

或 GitHub 集成:

  1. 推代码到 GitHub
  2. vercel.com 选 "New Project"
  3. 选仓库,自动构建

Vercel 自动配置:

  • Next.js 构建
  • 全球 CDN
  • 自动 HTTPS
  • 预览环境(每个 PR)

二、Docker 部署 ​

Dockerfile:

dockerfile
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci

FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]

next.config.js:

js
module.exports = {
  output: 'standalone',
};

构建运行:

bash
docker build -t my-app .
docker run -p 3000:3000 my-app

三、环境变量 ​

bash
# .env.local(不提交)
DATABASE_URL=postgres://...
NEXT_PUBLIC_API_URL=https://api.example.com
  • NEXT_PUBLIC_* 前缀的会暴露到客户端
  • 其他只在服务端可用
tsx
// 服务端
process.env.DATABASE_URL

// 客户端
process.env.NEXT_PUBLIC_API_URL

⚠️ 坑 1:不带 NEXT_PUBLIC_ 前缀的变量不会暴露到客户端,引用会是 undefined。

四、性能优化 ​

1. 图片优化 ​

tsx
import Image from 'next/image';

<Image src="/hero.jpg" width={1200} height={600} priority alt="hero" />

priority 给首屏大图,自动:

  • WebP/AVIF 转换
  • 懒加载
  • 防止 CLS

2. 字体优化 ​

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

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

无 FOIT(字体闪烁),自动子集化。

3. 代码分割 ​

tsx
import dynamic from 'next/dynamic';

const HeavyChart = dynamic(() => import('./Chart'), {
  ssr: false,
  loading: () => <Skeleton />,
});

4. Bundle 分析 ​

bash
npm install @next/bundle-analyzer
js
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true' });
module.exports = withBundleAnalyzer({});
bash
ANALYZE=true npm run build

五、React 18 并发特性实战 ​

1. useTransition(标记非紧急更新) ​

tsx
'use client';

import { useState, useTransition } from 'react';

function Search() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState<Result[]>([]);
  const [isPending, startTransition] = useTransition();

  function handleChange(e: ChangeEvent<HTMLInputElement>) {
    setQuery(e.target.value);                            // ⚠️ 紧急:立即更新
    startTransition(() => {                              // ✅ 非紧急:可中断
      setResults(filterLargeList(e.target.value));
    });
  }

  return (
    <>
      <input value={query} onChange={handleChange} />
      {isPending && <Spinner />}
      <Results data={results} />
    </>
  );
}

2. useDeferredValue(延迟值) ​

tsx
function Search() {
  const [query, setQuery] = useState('');
  const deferred = useDeferredValue(query);     // �️ 延迟一帧

  return (
    <>
      <input value={query} onChange={e => setQuery(e.target.value)} />
      <ExpensiveResults query={deferred} />     {/* 用 deferred 做重计算 */}
    </>
  );
}

3. Suspense for Data Fetching ​

tsx
import { Suspense } from 'react';

function App() {
  return (
    <Suspense fallback={<Skeleton />}>
      <UserProfile />
    </Suspense>
  );
}

async function UserProfile() {
  const user = await fetch('/api/user').then(r => r.json());
  return <div>{user.name}</div>;
}

4. 自动批处理(React 18+) ​

tsx
function Comp() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);

  function handle() {
    setA(1);
    setB(2);
    // ✅ React 18:只触发一次渲染
  }
}

六、错误监控 ​

bash
npm install @sentry/nextjs
npx @sentry/wizard@latest init
ts
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs';

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

七、SEO 与 metadata ​

tsx
// app/page.tsx
export const metadata = {
  title: '我的网站',
  description: 'Next.js 14 全栈教程',
  openGraph: {
    title: '我的网站',
    images: ['/og.png'],
  },
};

sitemap / robots ​

ts
// app/sitemap.ts
export default async function sitemap() {
  return [
    { url: 'https://example.com', lastModified: new Date() },
    { url: 'https://example.com/about', lastModified: new Date() },
  ];
}

八、缓存策略 ​

资源策略
HTML默认静态 / ISR
图片永久(内容哈希)
JS/CSS永久(内容哈希)
API 响应revalidate / no-store

九、监控与告警 ​

  • Vercel Analytics(免费,Web Vitals)
  • Sentry(错误监控)
  • Google Analytics(用户行为)
  • LogRocket(录屏回放)

十、React 19 预告(2025) ​

React 19 新特性:

  • React Compiler(自动优化 re-render)
  • use() API(Promise/Context 直接读)
  • ref 作为 prop(无需 forwardRef)
  • Server Actions 稳定
  • <form> action 自动 reset

⚠️ 坑 2:升级前看 react.dev/blog,部分破坏性变更(如 ref prop)。

十一、学习路径建议 ​

入门:HTML/CSS/JS → React 基础 → Hooks
进阶:TypeScript → Next.js → 性能优化
生态:Zustand/React Router → Tailwind/shadcn
工程:Vitest/Playwright → CI/CD → 监控
架构:Micro Frontends → Monorepo(Turborepo)

十二、本章小结 ​

要点关键
部署Vercel(零配置)/ Docker 自托管
环境变量NEXT_PUBLIC_* 暴露客户端
性能next/image、动态 import、bundle analyzer
并发useTransition / useDeferredValue / Suspense
监控Sentry + Vercel Analytics
React 19Compiler、use() API、ref prop

动手练习 ​

  1. Vercel 部署:把 Next.js 项目部署到 Vercel,看预览环境
  2. Bundle 分析:跑 ANALYZE=true,找出最大依赖,尝试拆动态加载
  3. useTransition:用 transition 包裹大列表过滤,感受输入不卡顿
  4. 错误监控:接入 Sentry,故意 throw 看是否上报

文档完结,React 18 + Next.js 14 全栈学习完成。

本站基于 VitePress 构建 · 由 StackHub 团队维护