Nuxt: 项目设计

最后更新:2026-08-26

Phase 1-4 的知识已经全部学完。现在 Charlie 要把所有知识融会贯通,设计一个完整的 MegaShop 电商平台。从需求分析到架构设计、从数据模型到 API 规范,这是实战项目的第一步。

1. 你将学到


2. 一个架构师的真实故事

(1) 痛点:没有设计直接开发

Charlie 之前让团队直接写代码,没有设计文档。结果:Alice 的购物车数据结构和 Bob 的订单数据不一致,API 命名混乱,数据库缺少索引查询慢,后期改动代价巨大。

(2) 系统设计的解法

先设计再开发——用 ER 图定义数据模型,用 RESTful 规范定义 API,用架构图定义系统边界。设计阶段多花 1 周,开发阶段省 3 周。

(3) 收益:清晰的蓝图

每个开发者看同一份设计文档,数据结构一致、API 规范统一、架构边界清晰,协作效率提升 3 倍。


3. 需求分析

(1) 用户角色与核心需求

角色 身份 核心需求 关键指标
Alice 消费者 浏览/搜索/加购/结算/评价 首屏 < 2s,搜索 < 500ms
Bob 管理员 商品管理/订单处理/用户管理 CRUD 响应 < 200ms
Charlie 架构师 系统稳定/高性能/可扩展 可用性 99.9%,支持 1M 商品

(2) 功能模块划分

模块 功能 优先级 涉及页面
认证 注册/登录/OAuth2/JWT P0 /login, /register
商品 CRUD/搜索/分类/筛选 P0 /products, /products/[id]
购物车 加购/改量/删除/清空 P0 /cart
订单 创建/支付/状态查询 P0 /checkout, /orders
用户 个人信息/地址/评价 P1 /profile
管理 后台CRUD/统计/审核 P1 /admin/**
国际化 中/英/日 + 多货币 P1 全局
SEO 动态meta/Sitemap/JSON-LD P0 商品页

4. 架构设计

(1) MegaShop 系统架构全景

100%
graph TB
    subgraph Client["Client Layer"]
        Browser[Browser / Mobile]
        Bot[Search Engine Bot]
    end

    subgraph CDN["CDN Layer"]
        CF[Cloudflare / Vercel Edge]
    end

    subgraph Nuxt["Nuxt 3 Application"]
        SSR[SSR Engine]
        ISR[ISR Cache]
        API[Nitro API Routes]
        MW[Middleware / Auth]
    end

    subgraph Data["Data Layer"]
        PG[(PostgreSQL)]
        Redis[(Redis Cache)]
        S3[Object Storage / Images]
    end

    subgraph External["External Services"]
        Stripe[Stripe Payment]
        Google[Google OAuth2]
        Analytics[Analytics Service]
    end

    Browser --> CDN
    Bot --> CDN
    CDN --> SSR
    CDN --> ISR
    SSR --> API
    API --> MW
    API --> PG
    API --> Redis
    API --> S3
    API --> Stripe
    API --> Google
    API --> Analytics
    ISR --> Redis

(2) 渲染策略设计

页面类型 渲染模式 swr 理由
首页 SSG - 内容稳定
商品列表 ISR 3600s 每小时更新
商品详情 ISR 86400s 每日更新
搜索结果 SSR - 实时查询
购物车/结算 CSR - 用户专属
管理后台 CSR - 无需 SEO
API 路由 动态 - 按需缓存

(3) 技术栈选型

▶ 示例:nuxt.config.ts 技术栈集成

TYPESCRIPT
// nuxt.config.ts - Full tech stack integration
export default defineNuxtConfig({
  ssr: true,
  modules: [
    '@pinia/nuxt',
    '@nuxtjs/tailwindcss',
    '@nuxtjs/i18n',
    '@nuxtjs/sitemap',
    '@nuxt/image',
    '~/modules/analytics'
  ],
  i18n: {
    locales: [
      { code: 'en', name: 'English', file: 'en.json', currency: 'USD' },
      { code: 'zh', name: '中文', file: 'zh.json', currency: 'CNY' },
      { code: 'ja', name: '日本語', file: 'ja.json', currency: 'JPY' }
    ],
    defaultLocale: 'en',
    lazy: true,
    langDir: 'locales/'
  },
  image: { quality: 80, format: ['webp', 'avif'] }
})

输出:

TEXT 📖 仅展示
// 执行成功

▶ 示例:Docker Compose 服务编排

YAML
# docker-compose.yml - Infrastructure definition
services:
  web:
    build: .
    ports: ["3000:3000"]
    depends_on: [db, redis]
  db:
    image: postgres:16-alpine
    volumes: [postgres_data:/var/lib/postgresql/data]
  redis:
    image: redis:7-alpine
    volumes: [redis_data:/data]
  nginx:
    image: nginx:alpine
    ports: ["80:80", "443:443"]
    depends_on: [web]

输出:

TEXT 📖 仅展示
CONTAINER ID   IMAGE          STATUS         PORTS
abc123         nginx:latest   Up 2 hours     0.0.0.0:80->80/tcp
层级 技术 选择理由
框架 Nuxt 3 SSR/ISR/CSR 混合渲染
UI Vue 3 + TailwindCSS 响应式 + 快速开发
状态管理 Pinia Vue 3 官方方案 + SSR 支持
数据库 PostgreSQL + Prisma 类型安全 ORM + 百万级查询
缓存 Redis + Nitro KV API 缓存 + ISR 存储
认证 JWT + OAuth2 无状态 + 社交登录
国际化 @nuxtjs/i18n 多语言 + SEO hreflang
图片 @nuxt/image WebP/AVIF + 响应式
测试 Vitest + Playwright 单元 + E2E
部署 Docker Compose 全套服务编排
CI/CD GitHub Actions 自动化流水线

5. 数据模型设计

(1) ER 图

100%
erDiagram
    User ||--o{ Order : "places"
    User ||--o{ Review : "writes"
    User ||--o{ CartItem : "has"
    User ||--o{ Address : "owns"
    Product ||--o{ OrderItem : "included in"
    Product ||--o{ CartItem : "added to"
    Product ||--o{ Review : "receives"
    Product ||--o{ ProductImage : "has"
    Product }o--|| Category : "belongs to"
    Category ||--o{ Category : "parent-child"
    Order ||--o{ OrderItem : "contains"
    Order }o--|| Address : "ships to"

(2) 核心表设计

▶ 示例:核心 Prisma Schema

PRISMA
// Key models from prisma/schema.prisma
model Product {
  id          Int       @id @default(autoincrement())
  name        String
  slug        String    @unique
  price       Decimal   @db.Decimal(10, 2)
  inStock     Boolean   @default(true)
  categoryId  Int
  category    Category  @relation(fields: [categoryId], references: [id])
  orderItems  OrderItem[]
  cartItems   CartItem[]
  @@index([categoryId])
  @@index([price])
}

model Order {
  id        Int       @id @default(autoincrement())
  userId    Int
  user      User      @relation(fields: [userId], references: [id])
  total     Decimal   @db.Decimal(10, 2)
  status    OrderStatus @default(PENDING)
  items     OrderItem[]
  @@index([userId])
  @@index([status])
}

输出:

TEXT 📖 仅展示
// 执行成功

▶ 示例:API 错误码定义

TYPESCRIPT
// server/utils/errors.ts
export const ErrorCodes = {
  VALIDATION_ERROR: { statusCode: 400, message: 'Validation error' },
  AUTH_REQUIRED: { statusCode: 401, message: 'Authentication required' },
  TOKEN_EXPIRED: { statusCode: 401, message: 'Token expired' },
  FORBIDDEN: { statusCode: 403, message: 'Insufficient permissions' },
  NOT_FOUND: { statusCode: 404, message: 'Resource not found' },
  CONFLICT: { statusCode: 409, message: 'Resource conflict' },
  RATE_LIMITED: { statusCode: 429, message: 'Too many requests' }
} as const

export function throwError(code: keyof typeof ErrorCodes, details?: any) {
  const err = ErrorCodes[code]
  throw createError({ statusCode: err.statusCode, message: err.message, data: { errorCode: code, details } })
}

输出:

TEXT 📖 仅展示
// 执行成功

▶ 示例:标准 API 响应格式

TYPESCRIPT
// server/utils/response.ts
export function successResponse(data: any, message = 'Success') {
  return { data, message, timestamp: Date.now() }
}

export function listResponse(items: any[], total: number, page: number, limit: number) {
  return { items, total, page, limit, timestamp: Date.now() }
}

export function errorResponse(statusCode: number, errorCode: string, message: string, details?: any) {
  return { statusCode, errorCode, message, details, timestamp: Date.now() }
}

输出:

TEXT 📖 仅展示
// 执行成功

▶ 示例:routeRules 渲染策略配置

TYPESCRIPT
// nuxt.config.ts - Route-level rendering strategy
routeRules: {
  '/': { prerender: true },
  '/products': { swr: 3600 },
  '/products/**': { swr: 86400 },
  '/admin/**': { ssr: false },
  '/cart': { ssr: false },
  '/api/**': { cors: true },
  '/_nuxt/**': { headers: { 'cache-control': 'public, max-age=31536000, immutable' } }
}

输出:

TEXT 📖 仅展示
// 执行成功

▶ 示例:CI/CD 流水线结构

YAML
# .github/workflows/ci.yml - Core pipeline
name: CI
on: [push, pull_request]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps: [{ uses: actions/checkout@v4 }, { run: npm ci }, { run: npm run lint }]
  test:
    needs: lint
    steps: [{ run: npm run test:coverage }]
  build:
    needs: test
    steps: [{ run: npm run build }]

输出:

TEXT 📖 仅展示
CI/CD pipeline loaded
Pipeline status: passed
Tests: 12 passed, 0 failed
字段数 核心索引 预估数据量
Product 12 slug, categoryId, price 1 million
Category 6 slug, parentId 500
User 10 email, role 500 thousand
Order 8 userId, status, createdAt 1 million
OrderItem 6 orderId, productId 5 million
CartItem 5 userId+productId(unique) 100 thousand
Review 7 productId, userId 2 million
Address 8 userId 500 thousand

6. API 规范

(1) RESTful API 设计

方法 路径 说明 鉴权
GET /api/products 商品列表(分页/筛选)
GET /api/products/:id 商品详情
POST /api/products 创建商品 Admin
PUT /api/products/:id 更新商品 Admin
DELETE /api/products/:id 删除商品 Admin
GET /api/categories 分类列表
POST /api/auth/register 注册
POST /api/auth/login 登录
POST /api/auth/refresh 刷新令牌 Cookie
GET /api/cart 购物车 User
POST /api/cart/add 加购 User
DELETE /api/cart/remove 移除 User
POST /api/orders 创建订单 User
GET /api/orders 订单列表 User
GET /api/orders/:id 订单详情 User

(2) 错误码规范

状态码 错误码 说明
400 VALIDATION_ERROR 请求参数校验失败
401 AUTH_REQUIRED 未登录
401 TOKEN_EXPIRED Token 过期
403 FORBIDDEN 权限不足
404 NOT_FOUND 资源不存在
409 CONFLICT 资源冲突(如邮箱已注册)
429 RATE_LIMITED 请求频率超限
500 INTERNAL_ERROR 服务器内部错误

(3) 响应格式

TYPESCRIPT
// Success response
{
  "data": { ... },
  "message": "Operation successful"
}

// List response
{
  "items": [...],
  "total": 1000000,
  "page": 1,
  "limit": 20
}

// Error response
{
  "statusCode": 400,
  "message": "Validation error",
  "errorCode": "VALIDATION_ERROR",
  "details": { "field": "email", "reason": "Invalid format" }
}

7. 综合示例:MegaShop 项目结构

TEXT 📖 仅展示
megashop/
├── nuxt.config.ts
├── prisma/
│   ├── schema.prisma
│   ├── seed.ts
│   └── migrations/
├── pages/
│   ├── index.vue
│   ├── products/
│   │   ├── index.vue
│   │   └── [id].vue
│   ├── categories/
│   │   └── [slug].vue
│   ├── cart.vue
│   ├── checkout.vue
│   ├── login.vue
│   ├── register.vue
│   ├── profile/
│   │   ├── index.vue
│   │   └── orders.vue
│   └── admin/
│       ├── index.vue
│       ├── products/
│       └── orders/
├── components/
│   ├── AppHeader.vue
│   ├── AppFooter.vue
│   ├── product/
│   │   ├── ProductCard.vue
│   │   ├── ProductGrid.vue
│   │   └── ProductReview.vue
│   ├── cart/
│   │   └── CartItem.vue
│   └── common/
│       ├── LanguageSwitcher.vue
│       └── SearchBar.vue
├── composables/
│   ├── useCart.ts
│   ├── useAnalytics.ts
│   ├── useLocalizedPrice.ts
│   └── useProductSearch.ts
├── stores/
│   ├── cart.ts
│   └── user.ts
├── server/
│   ├── utils/
│   │   ├── prisma.ts
│   │   └── jwt.ts
│   ├── middleware/
│   │   └── auth.ts
│   ├── api/
│   │   ├── auth/
│   │   ├── products/
│   │   ├── categories/
│   │   ├── cart/
│   │   └── orders/
│   └── plugins/
│       └── stock.ts
├── middleware/
│   ├── 01-auth.global.ts
│   └── admin.ts
├── plugins/
│   ├── 01-config.ts
│   ├── 02-logger.ts
│   └── 03-stripe.client.ts
├── layouts/
│   ├── default.vue
│   └── sidebar.vue
├── locales/
│   ├── en.json
│   ├── zh.json
│   └── ja.json
├── modules/
│   └── analytics/
├── tests/
│   ├── composables/
│   ├── stores/
│   ├── components/
│   └── api/
├── e2e/
│   ├── cart-flow.spec.ts
│   ├── auth-flow.spec.ts
│   └── admin-flow.spec.ts
├── Dockerfile
├── docker-compose.yml
├── .github/workflows/
│   ├── ci.yml
│   ├── deploy-staging.yml
│   └── deploy-production.yml
└── public/
    ├── favicon.ico
    └── robots.txt

❓ 常见问题

Q 设计阶段要花多少时间?
A 一般 1-2 周。需求分析 2 天、架构设计 2 天、数据模型 2 天、API 规范 2 天、技术选型 1 天。设计越细致,开发越顺畅。
Q PostgreSQL 和 MySQL 怎么选?
A PostgreSQL 更适合 MegaShop——支持 JSON 字段(商品属性)、全文搜索(商品搜索)、丰富的索引类型。Prisma 对 PostgreSQL 支持最好。
Q Redis 必须吗?
A 百万级商品页推荐使用。Redis 做商品缓存和 ISR 存储,响应 5ms vs 数据库 200ms。小流量可先不用。
Q API 版本管理怎么做?
A 在 URL 中加版本前缀 /api/v1/products,重大变更时升级版本。小版本变更用向后兼容的方式扩展字段。
Q 模块划分的粒度怎么定?
A 按业务领域划分——认证、商品、购物车、订单各一个模块。每个模块有独立的 API/Store/Composable/页面。不要按技术层划分。
Q 怎么保证设计文档和代码一致?
A 用 Prisma Schema 作为数据模型的 Single Source of Truth,API 规范用 TypeScript 接口定义。设计变更先改 Schema 和接口,再改代码。

📖 小节


📝 作业

  1. 基础题(难度⭐):画出你的项目用户角色和功能模块划分图
  2. 进阶题(难度⭐⭐):设计完整的 Prisma Schema(至少 5 个模型),考虑索引和外键
  3. 挑战题(难度⭐⭐⭐):设计完整的 API 规范文档,包括所有端点、请求/响应格式、错误码

---|

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏