关于 nextjs-shadcn-builder
用于创建 Next.js 应用或将现有前端迁移到 Next.js 和 shadcn/ui 的技能。它将代码分析、组件映射、分批转换和验证组织为流程,并强调设计令牌、响应式布局与无障碍性。
主要功能
- 01初始化带 App Router 的 Next.js
- 02分析前端代码库与组件
- 03规划并分批迁移组件
- 04将界面映射到 shadcn/ui 组件
- 05验证测试、响应式设计和无障碍性
适用场景
- 01启动 Next.js 应用
- 02迁移 React 前端
- 03转换 Vue 或 Angular 界面
- 04迁移期间统一样式
MCP 相关
工作流通过 shadcn MCP 服务查找组件、文档、区块、图表和设计令牌参考,并说明如何检查服务是否可用及在不可用时进行初始化。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ovachiever/ droid-tings --skill nextjs-shadcn-builder安装后在 Claude Code 中输入/nextjs-shadcn-builder确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdassets/theme-example-oklch.cssassets/component-templates/complex-form.tsxexample-feature-card.tsxexample-user-profile.tsxresponsive-dashboard.tsxresponsive-data-table.tsxresponsive-navigation.tsxreferences/accessibility-best-practices.mdadvanced-shadcn-components.mdreact-to-nextjs.mdresponsive-design-patterns.mdshadcn-component-mapping.mdstyling-migration.mdvue-to-nextjs.mdscripts/analyze-codebase.pydetect-hardcoded-values.shgenerate-migration-report.pyinit-nextjs-shadcn.sh详细介绍
Next.js + shadcn/ui 构建与迁移工具
构建可用于生产环境的 Next.js 应用,或按照严格的设计原则和最佳实践,将现有前端系统性地迁移到 Next.js + shadcn/ui。
概述
此技能支持两种主要工作流:
- 创建新的 Next.js 应用 - 使用 Next.js 15+(App Router)、shadcn/ui 和完善的设计系统配置初始化项目
- 迁移现有前端 - 分析任意前端代码库(React、Vue、Angular、原生 JavaScript),并系统性地将其转换为 Next.js + shadcn/ui
核心理念:100% 遵循 shadcn/ui 设计原则:
- 所有主题设置(颜色、间距、排版)都使用 CSS 变量
- 仅使用标准 shadcn/ui 组件(不使用自定义 UI 组件)
- 不使用硬编码值(颜色、间距、字体)
- 在整个应用中保持设计令牌一致
- 面向移动设备优先,为所有设备(手机、平板、桌面)提供响应式设计
- 符合 WCAG 2.1 AA 级无障碍标准
- 遵循 https://ui.shadcn.com 中的最佳实践
工作流决策树
User Request
├─ Creating New Next.js App
│ └─ Follow "Creating New Application" workflow (Phase 3 onwards)
│
└─ Migrating Existing Codebase
├─ Phase 1: Codebase Analysis
├─ Phase 2: Migration Planning
├─ Phase 3: Next.js + shadcn Setup
├─ Phase 4: Systematic Conversion
└─ Phase 5: Verification & Cleanup
迁移高级工作流
阶段 1:代码库分析
自动分析现有前端,以了解范围和复杂程度。
步骤:
- 检测框架和版本
- 盘点组件并进行分类
- 检测硬编码值(颜色、间距、自定义组件)
- 分析样式方案(CSS、SCSS、CSS-in-JS、Tailwind 等)
- 识别状态管理和路由模式
- 生成全面的分析报告
交付内容:
- 框架分析报告
- 组件清单(JSON)
- 硬编码值报告
- 复杂度评估
阶段 2:迁移规划
制定系统化转换计划,并按优先级分批处理。
步骤:
- 将现有组件映射到对应的 shadcn/ui 组件
- 确定需要自定义开发的组件
- 将转换工作分批组织(每批 5-10 个组件)
- 评估每批的风险和复杂程度
- 制定详细的迁移计划
交付内容:
- 组件映射表
- 分批转换计划
- 风险评估
- 各组件的预估复杂度
阶段 3:Next.js + shadcn 配置
在现有代码库旁初始化 Next.js 基础设施,或用其替换现有代码库。
步骤:
- 检查并安装 shadcn MCP 服务,以访问文档
- 使用 App Router 和 TypeScript 初始化 Next.js 15+
- 安装并配置 Tailwind CSS
- 运行 shadcn/ui 初始化
- 设置 CSS 变量和设计令牌
- 配置路径别名(@/)
- 安装必要的 shadcn 组件
- 创建设计系统文档
交付内容:
- 配置完成的 Next.js 项目
- 设计令牌系统(CSS 变量)
- 组件库配置
- 已配置路径别名
阶段 4:系统化转换
分批转换组件,并在每批完成后进行测试。
步骤:
- 第 1 批:布局与结构(页眉、页脚、布局包装器)
- 第 2 批:简单 UI 组件(按钮、卡片、徽章、警告框)
- 第 3 批:表单组件(输入框、选择框、复选框、表单)
- 第 4 批:复杂组件(表格、对话框、命令菜单、数据可视化)
- 第 5 批:样式标准化(移除硬编码值,应用 CSS 变量)
- 第 6 批:页面与路由(转换页面,设置 Next.js 路由)
每批工作流:
- 选择 5-10 个相关组件
- 使用 MCP 查找合适的 shadcn 组件
- 按照 shadcn 模式转换组件
- 将硬编码值替换为 CSS 变量
- 测试功能
- 检查视觉一致性
- 继续下一批
交付内容:
- 已迁移的组件(逐批完成)
- 使用 CSS 变量更新的样式
- Next.js App Router 页面
- 每批均通过测试
阶段 5:验证与清理
最终测试、优化并移除旧代码。
步骤:
- 运行完整测试套件
- 视觉回归测试
- 响应式设计测试(移动设备、平板电脑、桌面设备)
- 性能审查
- 无障碍审查(符合 WCAG 2.1 AA 级标准)
- 移除旧框架代码
- 更新文档
- 生成完成报告
交付物:
- 测试结果
- 响应式设计验证报告
- 性能指标
- 无障碍审查报告(WCAG 2.1 AA)
- 整洁的代码库
- 迁移摘要
阶段 1:代码库分析(详细说明)
1.1 框架检测
运行自动化分析脚本:
python ./scripts/analyze-codebase.py /path/to/existing/codebase
此脚本将:
- 检测框架(React、Vue、Angular、Svelte、vanilla JS 等)
- 识别框架版本
- 检测构建工具(Vite、Webpack、Parcel 等)
- 查找 package.json 依赖项
- 映射目录结构
输出: 包含框架元数据的 codebase-analysis.json
1.2 组件清单
分析脚本会自动生成组件清单,包括:
- 组件名称和文件路径
- 组件类型(函数式、类、Vue SFC 等)
- Props/输入
- 状态用法
- 子组件
- 外部依赖项
输出: component-inventory.json
结构示例:
{
"components": [
{
"name": "UserCard",
"path": "src/components/UserCard.tsx",
"type": "functional",
"complexity": "simple",
"shadcn_equivalent": "Card",
"hardcoded_values": ["#3b82f6", "16px padding"],
"dependencies": ["react", "styled-components"]
}
]
}
1.3 硬编码值检测
运行检测脚本:
bash ./scripts/detect-hardcoded-values.sh /path/to/existing/codebase
此脚本可检测:
- 硬编码颜色:
#hex、rgb()、rgba()、hsl()、颜色名称 - 内联间距:
margin: 20px、padding: 1rem - 自定义字体声明:非标准字体
- 魔法数字:组件中的任意值
- 内联样式:
style={{...}} - 非标准模式:应使用 Tailwind 的 CSS-in-JS、styled-components
输出: 按类别归纳违规项的 hardcoded-values-report.md
1.4 生成分析报告
运行报告生成器:
python ./scripts/generate-migration-report.py
此操作会将所有分析数据整合为一份完整的 Markdown 报告:
输出: migration-analysis-report.md
# Frontend Migration Analysis Report
## Executive Summary
[One-paragraph overview: framework, size, complexity]
## Current State Analysis
- **Framework**: React 18.2.0
- **Build Tool**: Vite 4.3.0
- **Component Count**: 47 components
- **Styling**: styled-components + custom CSS
- **State Management**: Redux Toolkit
- **Routing**: React Router v6
## Hardcoded Values Detected
- Colors: 142 instances across 34 files
- Spacing: 89 instances across 28 files
- Custom fonts: 3 non-standard fonts
- Inline styles: 67 instances
## Component Categorization
- **Simple (shadcn mapping exists)**: 28 components
- **Moderate (requires adaptation)**: 13 components
- **Complex (custom development needed)**: 6 components
## Recommended Migration Plan
1. Phase 3: Setup Next.js + shadcn infrastructure
2. Phase 4.1: Convert layout components (Header, Footer, Layout)
3. Phase 4.2: Convert simple UI (Button, Card, Badge → shadcn equivalents)
4. Phase 4.3: Convert forms (Input, Select → shadcn/ui Form components)
5. Phase 4.4: Convert complex components (DataTable, Charts)
6. Phase 4.5: Styling standardization (CSS variables)
7. Phase 4.6: Pages and routing
8. Phase 5: Verification and cleanup
## Estimated Effort
- **Total Components**: 47
- **Batches**: 9-10 batches
- **Complexity**: Moderate
阶段 2:迁移规划(详细说明)
2.1 组件映射策略
查看 component-inventory.json,并使用 shadcn 组件参考资料创建映射表。
非常重要:使用 MCP 发现 shadcn 组件
映射前,检查 shadcn MCP 服务是否可用:
# Check if MCP server is available
# Try accessing https://ui.shadcn.com/docs/mcp
如果 MCP 不可用,请安装:
npx shadcn@latest mcp init --client claude
使用 MCP 查询可用组件:
- “shadcn 中有哪些按钮组件?”
- “展示 shadcn 中的表单组件”
- “shadcn 中与模态框/对话框等效的组件是什么?”
- “shadcn 中有哪些数据展示组件?”
组件映射表模板:
| 现有组件 | shadcn 等效组件 | 复杂度 | 优先级 | 备注 |
|---|---|---|---|---|
| CustomButton | Button | 低 | 1 | Props 大多兼容 |
| Modal | Dialog | 中 | 2 | API 不同,使用 Radix |
| DataTable | Table + DataTable | 高 | 3 | 需要自定义钩子 |
| Dropdown | DropdownMenu | 低 | 1 | 可直接映射 |
| DatePicker | Calendar + Popover | 中 | 2 | 组合模式 |
加载特定框架的迁移指南:
- 对于 React:阅读
./references/react-to-nextjs.md - 对于 Vue:阅读
./references/vue-to-nextjs.md - 对于 Angular:阅读
./references/angular-to-nextjs.md - 对于样式:阅读
./references/styling-migration.md
2.2 批次组织
按照以下原则将组件组织为多个批次:
批次策略:
- 按类型分组(布局、表单、数据展示、导航)
- 由简单到复杂(从容易完成的任务开始)
- 按依赖顺序排列(先转换依赖项)
- 批次规模:每批 5-10 个组件
批次计划示例:
批次 1:布局与结构(优先级:关键)
- Header
- Footer
- MainLayout
- Container
- Sidebar
批次 2:简单 UI 组件(优先级:高)
- Button → shadcn Button
- Card → shadcn Card
- Badge → shadcn Badge
- Alert → shadcn Alert
- Avatar → shadcn Avatar
批次 3:表单组件(优先级:高)
- Input → shadcn Input
- Select → shadcn Select
- Checkbox → shadcn Checkbox
- RadioGroup → shadcn RadioGroup
- 表单验证 → shadcn Form + react-hook-form
批次 4:导航(优先级:中)
- NavBar → shadcn NavigationMenu
- Breadcrumbs → shadcn Breadcrumb
- Tabs → shadcn Tabs
- Pagination → shadcn Pagination
批次 5:数据展示(优先级:中)
- Table → shadcn Table
- DataGrid → shadcn DataTable(含排序、筛选)
- List → shadcn 自定义组合
- Accordion → shadcn Accordion
批次 6:覆盖层与模态框(优先级:中)
- Modal → shadcn Dialog
- Tooltip → shadcn Tooltip
- Popover → shadcn Popover
- DropdownMenu → shadcn DropdownMenu
批次 7:复杂组件(优先级:低)
- Charts → shadcn Charts(集成 Recharts)
- Calendar/DatePicker → shadcn Calendar
- CommandPalette → shadcn Command
- DataVisualization → 使用 shadcn 基元自定义实现
批次 8:样式标准化(优先级:关键)
- 提取所有硬编码颜色 → CSS 变量
- 将间距转换为 Tailwind 类
- 统一字体排版
- 一致地应用主题系统
批次 9:页面与路由(优先级:关键)
- 将页面转换为 Next.js App Router
- 使用 Next.js layout.tsx 设置布局
- 实现路由模式
- 添加加载和错误状态
2.3 风险评估
针对每个批次,识别风险:
- API 差异:API 差异显著的组件
- 功能缺失:旧组件中有而 shadcn 中没有的功能
- 状态管理:需要重构的复杂状态
- 依赖项:需要替换的外部库
- 自定义逻辑:与 UI 紧密耦合的业务逻辑
风险缓解:
- 在转换前记录 API 差异
- 必要时创建适配器/包装组件
- 在迁移前编写测试
- 在过渡期间暂时保留旧组件
2.4 创建详细的迁移计划
生成详细的计划文档:migration-plan.md
# Next.js + shadcn Migration Plan
## Project: [Project Name]
## Date: [Current Date]
## Estimated Timeline: [X batches]
## Migration Strategy
### Approach
- Incremental migration with parallel running old and new code
- Batch-based conversion (5-10 components per batch)
- Test after each batch before proceeding
- Feature flag new components during transition
### Success Criteria
- All components use shadcn/ui or shadcn patterns
- Zero hardcoded colors/spacing (CSS variables only)
- 100% TypeScript coverage
- Passing test suite
- Lighthouse score >= 90
- No accessibility violations
## Detailed Batch Plan
[Include all batches from 2.2 with specific components listed]
## Timeline
Batch 1: Layout & Structure (Days 1-2)
Batch 2: Simple UI (Days 3-4)
[etc.]
## Notes and Considerations
[Any special requirements, blockers, or dependencies]
阶段 3:Next.js + shadcn 设置(详细说明)
3.1 检查/安装 shadcn MCP 服务
重要:始终使用 MCP 发现 shadcn 组件
-
检查 MCP 服务是否可访问:
- 尝试访问
https://ui.shadcn.com/docs/mcp中的文档 - 检查能否通过 MCP 查询 shadcn 组件
- 尝试访问
-
如果不可用,请安装 MCP 服务:
npx shadcn@latest mcp init --client claude
这将启用:
- 实时访问 shadcn 文档
- 组件发现与搜索
- 区块和图表模板发现
- 主题和设计令牌参考
开发期间使用 MCP:
- “针对[使用场景]有哪些可用组件?”
- “显示 shadcn Button 的 props”
- “shadcn 中有哪些可用的图表类型?”
- “如何使用 shadcn Form 进行验证?”
3.2 初始化 Next.js 项目
运行初始化脚本:
bash ./scripts/init-nextjs-shadcn.sh [project-name]
或手动初始化:
# Check Node.js version (18+ required)
node -v
# Create Next.js project with App Router
npx create-next-app@latest [project-name] \
--typescript \
--tailwind \
--app \
--src-dir \
--import-alias "@/*" \
--no-turbopack
cd [project-name]
3.3 安装并配置 shadcn/ui
# Initialize shadcn/ui
npx shadcn@latest init
# Configuration prompts:
# - TypeScript: Yes
# - Style: Default
# - Base color: Choose from slate/gray/zinc/neutral/stone
# - CSS variables: Yes (CRITICAL - required for theming)
# - Import alias: @/components
这将创建:
components.json配置文件- 包含 cn() 助手函数的
lib/utils.ts - 更新后的 shadcn 主题
tailwind.config.ts app/globals.css中的 CSS 变量
3.4 配置设计令牌(CSS 变量)
非常重要:所有主题样式都必须使用 CSS 变量
颜色格式:OKLCH(推荐)
此技能使用 OKLCH(OKLab 亮度、彩度、色相)色彩空间,而不是 HSL,以获得更好的感知均匀性和色彩准确度。
OKLCH 的优点:
- 感知均匀(相同的变化 = 相同的感知差异)
- 渐变插值效果更好
- 亮度更可预测
- 更适用于无障碍设计(对比度更准确)
编辑 app/globals.css 以定义设计系统:
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--radius: 0.65rem;
/* Background - Pure white */
--background: 1 0 0;
--foreground: 0.141 0.005 285.823;
/* Card */
--card: 1 0 0;
--card-foreground: 0.141 0.005 285.823;
/* Popover */
--popover: 1 0 0;
--popover-foreground: 0.141 0.005 285.823;
/* Primary - Warm orange */
--primary: 0.646 0.222 41.116;
--primary-foreground: 0.98 0.016 73.684;
/* Secondary - Light purple-gray */
--secondary: 0.967 0.001 286.375;
--secondary-foreground: 0.21 0.006 285.885;
/* Muted - Subtle elements */
--muted: 0.967 0.001 286.375;
--muted-foreground: 0.552 0.016 285.938;
/* Accent */
--accent: 0.967 0.001 286.375;
--accent-foreground: 0.21 0.006 285.885;
/* Destructive - Red */
--destructive: 0.577 0.245 27.325;
/* Border and Input */
--border: 0.92 0.004 286.32;
--input: 0.92 0.004 286.32;
/* Focus ring */
--ring: 0.75 0.183 55.934;
/* Chart colors */
--chart-1: 0.837 0.128 66.29;
--chart-2: 0.705 0.213 47.604;
--chart-3: 0.646 0.222 41.116;
--chart-4: 0.553 0.195 38.402;
--chart-5: 0.47 0.157 37.304;
}
.dark {
/* Dark mode backgrounds */
--background: 0.141 0.005 285.823;
--foreground: 0.985 0 0;
/* Dark mode card */
--card: 0.21 0.006 285.885;
--card-foreground: 0.985 0 0;
/* Dark mode popover */
--popover: 0.21 0.006 285.885;
--popover-foreground: 0.985 0 0;
/* Dark mode primary - Brighter for contrast */
--primary: 0.705 0.213 47.604;
--primary-foreground: 0.98 0.016 73.684;
/* Dark mode secondary */
--secondary: 0.274 0.006 286.033;
--secondary-foreground: 0.985 0 0;
/* Dark mode muted */
--muted: 0.274 0.006 286.033;
--muted-foreground: 0.705 0.015 286.067;
/* Dark mode accent */
--accent: 0.274 0.006 286.033;
--accent-foreground: 0.985 0 0;
/* Dark mode destructive */
--destructive: 0.704 0.191 22.216;
/* Dark mode borders (with alpha) */
--border: 1 0 0 / 10%;
--input: 1 0 0 / 15%;
/* Dark mode focus ring */
--ring: 0.408 0.123 38.172;
/* Chart colors (consistent) */
--chart-1: 0.837 0.128 66.29;
--chart-2: 0.705 0.213 47.604;
--chart-3: 0.646 0.222 41.116;
--chart-4: 0.553 0.195 38.402;
--chart-5: 0.47 0.157 37.304;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
为迁移的项目自定义:
如果要迁移已有设计系统的应用,请提取现有颜色并映射到 CSS 变量:
# Use the detection script to find existing colors
bash ./scripts/detect-hardcoded-values.sh /path/to/old/codebase
# Map old colors to new CSS variables (OKLCH format)
# Use https://oklch.com or https://colorjs.io to convert
# Example:
# Old: #FF6B35 (brand orange) → --primary: 0.646 0.222 41.116
# Old: #3B82F6 (blue) → --primary: 0.630 0.213 255.5
# Old: #10B981 (green) → --success: 0.710 0.180 165.4
3.5 安装必要的 shadcn 组件
使用 MCP 查找所需组件!
安装核心组件:
# Layout & Structure
npx shadcn@latest add card
npx shadcn@latest add separator
# Forms
npx shadcn@latest add button
npx shadcn@latest add input
npx shadcn@latest add label
npx shadcn@latest add select
npx shadcn@latest add checkbox
npx shadcn@latest add radio-group
npx shadcn@latest add form
# Navigation
npx shadcn@latest add navigation-menu
npx shadcn@latest add tabs
npx shadcn@latest add breadcrumb
# Feedback
npx shadcn@latest add alert
npx shadcn@latest add toast
npx shadcn@latest add dialog
npx shadcn@latest add tooltip
# Data Display
npx shadcn@latest add table
npx shadcn@latest add badge
npx shadcn@latest add avatar
# Overlays
npx shadcn@latest add popover
npx shadcn@latest add dropdown-menu
npx shadcn@latest add sheet
在开发过程中,根据需要通过 MCP 查询其他组件。
3.6 设置主题提供程序(支持深色模式)
安装 next-themes:
npm install next-themes
创建 components/theme-provider.tsx:
"use client"
import * as React from "react"
import { ThemeProvider as NextThemesProvider } from "next-themes"
import { type ThemeProviderProps } from "next-themes/dist/types"
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}
更新 app/layout.tsx:
import { ThemeProvider } from "@/components/theme-provider"
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
{children}
</ThemeProvider>
</body>
</html>
)
}
3.7 创建示例组件
创建 components/example-card.tsx,展示最佳实践:
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
export function ExampleCard() {
return (
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle>shadcn/ui Best Practices</CardTitle>
<CardDescription>
This card demonstrates proper shadcn patterns
</CardDescription>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">
Notice: No hardcoded colors, using CSS variables via Tailwind classes,
standard shadcn components, and proper typography scale.
</p>
</CardContent>
<CardFooter className="flex justify-between">
<Button variant="outline">Cancel</Button>
<Button>Continue</Button>
</CardFooter>
</Card>
)
}
展示的关键模式:
- 使用标准 shadcn 组件(Card、Button)
- 不使用硬编码颜色(使用
text-muted-foreground) - 通过 Tailwind 自动应用 CSS 变量
- 语义化变体(
outline、默认) - 合理组合组件
第 4 阶段:系统化转换(详细说明)
4.1 组件转换工作流
每批处理 5–10 个组件:
步骤 1:检查本批次的组件
加载组件文件并了解:
- 当前功能
- Props/API
- 样式方案
- 状态管理
- 事件处理程序
步骤 2:查询 MCP,查找 shadcn 对应组件
转换前,使用 MCP:
- “哪种 shadcn 组件适用于 [组件类型]?”
- “展示 shadcn [组件] 的 props 和示例”
- “如何将 shadcn [组件] 与 [功能] 配合使用?”
步骤 3:转换组件
遵循以下模式:
// OLD: Custom button with hardcoded styles
const CustomButton = ({ children, onClick, variant = 'primary' }) => {
const styles = {
primary: {
backgroundColor: '#3b82f6', // HARDCODED!
color: '#ffffff',
padding: '8px 16px', // HARDCODED!
borderRadius: '6px'
},
secondary: {
backgroundColor: '#6b7280',
color: '#ffffff',
padding: '8px 16px',
borderRadius: '6px'
}
}
return (
<button style={styles[variant]} onClick={onClick}>
{children}
</button>
)
}
// NEW: shadcn Button with CSS variables
import { Button } from "@/components/ui/button"
const CustomButton = ({ children, onClick, variant = 'default' }) => {
return (
<Button variant={variant} onClick={onClick}>
{children}
</Button>
)
}
转换检查清单:
- ✅ 替换为 shadcn 组件
- ✅ 移除所有硬编码颜色
- ✅ 移除内联样式
- ✅ 仅使用 Tailwind 类
- ✅ 使用语义化变体(default、outline、destructive 等)
- ✅ 保留所有功能
- ✅ 正确定义 TypeScript 类型
步骤 4:将硬编码值替换为 CSS 变量
// OLD: Hardcoded spacing and colors
<div style={{
backgroundColor: '#f3f4f6', // WRONG
padding: '20px', // WRONG
margin: '10px 0' // WRONG
}}>
// NEW: Tailwind classes using CSS variables
<div className="bg-secondary p-5 my-2.5">
// Or for custom spacing:
<div className="bg-secondary" style={{ padding: 'var(--spacing-5)' }}>
步骤 5:测试功能
转换每个组件后:
# Run tests
npm test
# Visual testing
npm run dev
# Manually verify component renders correctly
步骤 6:确认不存在违规项
对新组件运行检测脚本:
bash ./scripts/detect-hardcoded-values.sh src/components/[batch-name]
应返回 0 个违规项。
步骤 7:完成本批次,继续下一批
更新待办列表和 migration-plan.md 中的进度。
4.2 常见组件迁移
详细映射请参阅 ./references/shadcn-component-mapping.md。
快速参考:
| 模式 | 旧方案 | shadcn 方案 |
|---|---|---|
| 按钮 | 自定义样式按钮 | <Button variant="..."> |
| 模态框/对话框 | 自定义遮罩层 | <Dialog> 与 <DialogTrigger> 和 <DialogContent> |
| 表单输入 | 带验证的自定义输入框 | <Form> + <FormField> + react-hook-form |
| 下拉菜单 | 自定义选择框 | <Select> 或 <DropdownMenu> |
| 表格 | 自定义表格 | <Table> 或 DataTable 模式 |
| 工具提示 | 自定义悬停组件 | <Tooltip> |
| Toast/通知 | 自定义通知 | useToast() hook + <Toaster> |
| 选项卡 | 自定义选项卡组件 | <Tabs> 与 <TabsList> 和 <TabsContent> |
| 卡片 | 自定义卡片 | <Card> 与子组件 |
| 徽章 | 自定义徽章/胶囊标签 | <Badge variant="..."> |
4.3 处理复杂组件
对于没有直接对应 shadcn 组件的组件:
选项 1:组合
使用 shadcn 基础组件构建:
// Complex dashboard widget using shadcn primitives
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
export function DashboardWidget({ title, data, onRefresh }) {
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>{title}</CardTitle>
<Button variant="outline" size="sm" onClick={onRefresh}>
Refresh
</Button>
</CardHeader>
<CardContent>
{data.map(item => (
<div key={item.id} className="flex items-center justify-between py-2">
<span className="text-sm">{item.label}</span>
<Badge variant={item.status === 'success' ? 'default' : 'destructive'}>
{item.value}
</Badge>
</div>
))}
</CardContent>
</Card>
)
}
选项 2:扩展 shadcn 组件
创建扩展 shadcn 的自定义组件:
// Custom component extending shadcn Button
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"
interface IconButtonProps extends React.ComponentProps<typeof Button> {
icon: React.ReactNode
}
export function IconButton({ icon, children, className, ...props }: IconButtonProps) {
return (
<Button className={cn("flex items-center gap-2", className)} {...props}>
{icon}
{children}
</Button>
)
}
选项 3:使用 shadcn Blocks
使用 MCP 查找 shadcn blocks(预构建的复杂组件):
“shadcn 中有哪些适用于 [use case] 的 blocks?”
安装 blocks:
npx shadcn@latest add [block-name]
4.4 页面和路由转换
将页面转换为 Next.js App Router 结构:
旧结构(React Router):
src/
pages/
Home.tsx
About.tsx
Dashboard.tsx
users/
UserList.tsx
UserDetail.tsx
新结构(Next.js App Router):
app/
page.tsx # Home
about/
page.tsx # About
dashboard/
page.tsx # Dashboard
layout.tsx # Dashboard layout
users/
page.tsx # UserList
[id]/
page.tsx # UserDetail
layout.tsx # Root layout
loading.tsx # Loading state
error.tsx # Error boundary
转换示例:
// OLD: React Router page
// src/pages/Dashboard.tsx
import { useNavigate } from 'react-router-dom'
export function Dashboard() {
const navigate = useNavigate()
return (
<div style={{ padding: '20px' }}>
<h1>Dashboard</h1>
<button onClick={() => navigate('/users')}>
View Users
</button>
</div>
)
}
// NEW: Next.js App Router page
// app/dashboard/page.tsx
import Link from 'next/link'
import { Button } from '@/components/ui/button'
export default function DashboardPage() {
return (
<div className="container py-6">
<h1 className="text-3xl font-bold mb-6">Dashboard</h1>
<Link href="/users">
<Button>View Users</Button>
</Link>
</div>
)
}
主要变更:
- 页面使用默认导出
- 使用 Next.js
<Link>替代路由导航 - 移除硬编码的内边距 → 使用 Tailwind 类
- 使用 shadcn Button
4.5 状态管理迁移
加载参考资料: ./references/react-to-nextjs.md,了解状态管理模式
常见模式:
本地状态(useState):
- 在 Next.js App Router 中保持不变
- 使用
"use client"标记客户端组件
全局状态:
- Redux → Zustand 或 React Context
- MobX → Zustand
- Recoil → Zustand 或 Jotai
服务端状态:
- React Query → TanStack Query(在 Next.js 中仍可使用)
- SWR → SWR(兼容 Next.js)
- 或使用 Next.js Server Components 获取服务端数据
第 5 阶段:验证与清理(详细说明)
5.1 运行测试套件
# Run all tests
npm test
# Run with coverage
npm test -- --coverage
# Ensure 100% of migrated components have passing tests
5.2 视觉回归测试
手动验证清单:
- 所有页面均可正确渲染
- 所有组件均符合设计系统
- 深色模式运行正常
- 保持响应式设计
- 不显示硬编码颜色
- 整体间距保持一致
- 排版符合设计系统
可选:使用 Percy、Chromatic 或 Playwright 设置自动化视觉回归测试。
5.3 响应式设计测试
关键:在真实设备上测试,而不仅仅是使用浏览器 DevTools
参考: ./references/responsive-design-patterns.md,查看完整的响应式测试指南。
设备测试清单:
- iPhone SE(320px - 现代视口中的最小尺寸)
- iPhone 14 Pro(390px)
- iPad(768px)
- iPad Pro(1024px)
- 桌面设备(1280px - 1920px)
- 超宽屏(2560px+)
方向测试:
- 手机/平板竖屏模式
- 手机/平板横屏模式
- 旋转设备时的响应行为
响应式模式验证:
- 导航:手机汉堡菜单 → 平板侧边栏 → 桌面导航栏
- 数据表格:手机卡片 → 平板可滚动表格 → 桌面完整表格
- 网格:手机 1 列 → 平板 2 列 → 桌面 3-4 列
- 表单:手机单列 → 桌面多列
- 触控目标:手机上最小尺寸为 44x44px
- 排版:在所有屏幕尺寸下均清晰易读(正文最小字号为 16px)
- 图片:采用响应式尺寸并保持正确的宽高比
断点验证:
# Test all Tailwind breakpoints
# sm: 640px, md: 768px, lg: 1024px, xl: 1280px, 2xl: 1536px
# Verify components respond correctly at each breakpoint
组件示例:
查看 ./assets/component-templates/ 中的响应式设计示例:
responsive-navigation.tsx- 手机/平板/桌面导航模式responsive-data-table.tsx- 带手机卡片布局的响应式表格responsive-dashboard.tsx- 响应式网格布局complex-form.tsx- 多步骤响应式表单
5.4 最后检查硬编码值
bash ./scripts/detect-hardcoded-values.sh src/
预期结果: 0 项违规
如果发现违规项,请返回第 4 阶段并修复。
5.5 无障碍审计(WCAG 2.1 AA 级)
关键:达到 WCAG 2.1 AA 级合规要求
参考: ./references/accessibility-best-practices.md,了解全面的无障碍测试指南。
# Install axe DevTools or use Lighthouse
npm install -D @axe-core/playwright
# Run accessibility tests
npm run test:a11y
shadcn/ui 组件在设计时考虑了无障碍性(使用 Radix UI 基元),但仍需验证:
自动化测试:
- 在所有页面上运行 axe DevTools 浏览器扩展
- Lighthouse 无障碍评分 >= 90
- 自动化工具未报告任何 WCAG 违规问题
- eslint-plugin-jsx-a11y 检查通过(如已配置)
键盘导航(WCAG 2.1.1、2.1.2):
- 所有交互元素均可通过 Tab 键访问
- Tab 顺序合理(与视觉布局一致)
- 不存在键盘陷阱(可通过 Tab 键移出所有组件)
- 按 Enter/Space 键可激活按钮/链接
- 按 Escape 键可关闭模态框/对话框
- 可使用方向键在组件内部导航(标签页、菜单、单选组)
- 所有交互元素均显示清晰的焦点指示器
屏幕阅读器测试: 使用实际的屏幕阅读器进行测试:
- macOS:VoiceOver(Cmd + F5)
- Windows:NVDA(免费)或 JAWS
- 移动设备:VoiceOver(iOS)或 TalkBack(Android)
屏幕阅读器检查清单(WCAG 1.3.1、4.1.2):
- 所有图像均有替代文本
- 表单输入框均有关联的标签
- 按钮有描述性文本或 aria-label
- 标题遵循逻辑层级(h1 → h2 → h3)
- 页面区域标记齐全(header、nav、main、aside、footer)
- 通过 aria-live 区域播报动态内容
- 向屏幕阅读器播报错误消息
颜色对比度(WCAG 1.4.3):
- 正文文本:对比度至少为 4.5:1
- 大号文本(18pt+):对比度至少为 3:1
- UI 组件:对比度至少为 3:1
- 焦点指示器:对比度至少为 3:1
- 测试浅色和深色模式
表单无障碍性(WCAG 3.3.1、3.3.2):
- 所有输入框均有可见标签
- 清晰标明必填字段
- 错误消息具体且有帮助
- 错误消息与输入框相关联(aria-describedby)
- 表单验证不单靠颜色提示
触控目标(WCAG 2.5.5):
- 移动设备上的所有触控目标至少为 44x44 CSS 像素
- 触控目标之间间距充足(至少 8px)
ARIA 用法(WCAG 4.1.2):
- 仅含图标的按钮使用 ARIA 标签
- 可折叠区域使用 aria-expanded
- 标签页使用 aria-selected
- 装饰性元素使用 aria-hidden
- 错误消息使用 role="alert"
- 非关键更新使用 role="status"
完整 WCAG 2.1 AA 检查清单:
完整的 WCAG 2.1 AA 级检查清单请参阅 ./references/accessibility-best-practices.md。
5.6 性能审计
# Build for production
npm run build
# Analyze bundle
npm run analyze # If you have bundle analyzer configured
运行 Lighthouse 审计:
- 性能 >= 90
- 无障碍性 >= 90
- 最佳实践 >= 90
- SEO >= 90
性能检查清单:
- Core Web Vitals 达到“良好”阈值
- LCP(最大内容绘制)< 2.5s
- FID(首次输入延迟)< 100ms
- CLS(累积布局偏移)< 0.1
- 优化图像(使用 Next.js Image 组件)
- 为大型组件实现代码拆分
- 对首屏以下内容进行延迟加载
- 包体积合理(使用 bundle analyzer 检查)
5.7 移除旧代码
确认迁移无误后:
# Remove old framework code
rm -rf src/old-components/ # or whatever old structure was
# Remove old dependencies
npm uninstall [old-framework] [old-ui-library] styled-components emotion ...
# Clean up old config files
rm -f .babelrc webpack.config.js # etc.
5.8 生成完成报告
创建 migration-complete-report.md:
# Migration Completion Report
## Summary
Successfully migrated [Project Name] from [Old Framework] to Next.js + shadcn/ui.
## Statistics
- **Components Migrated**: 47
- **Lines of Code Changed**: ~5,200
- **Hardcoded Values Removed**: 231
- **CSS Variables Added**: 48
- **shadcn Components Used**: 18
## Test Results
- **Unit Tests**: 142/142 passing
- **Integration Tests**: 23/23 passing
- **Accessibility Score**: 98/100
- **Lighthouse Performance**: 94/100
## Before/After Comparison
### Before
- Framework: React 18 + Vite
- Styling: styled-components + custom CSS
- Hardcoded values: 231 violations
- Bundle size: 523 KB
- Lighthouse: 76
### After
- Framework: Next.js 15 + App Router
- Styling: Tailwind CSS + shadcn/ui
- Hardcoded values: 0 violations
- Bundle size: 398 KB (24% reduction)
- Lighthouse: 94 (23% improvement)
## Design System
All components now use CSS variables defined in globals.css:
- 24 color tokens
- 12 spacing tokens
- 8 typography tokens
- Full dark mode support
## Next Steps
- Deploy to production
- Monitor performance metrics
- Gather user feedback
- Optional: Implement additional shadcn blocks
shadcn 设计原则(关键)
核心原则
1. 使用 CSS 变量进行所有主题设置
- 绝不要硬编码颜色、间距或排版样式
- 在
globals.css中将所有设计令牌定义为 CSS 变量 - 使用引用这些变量的 Tailwind 类
2. 仅使用标准组件
- 原样使用 shadcn/ui 组件
- 通过组合扩展,而非修改组件
- 如果 shadcn 没有所需组件,则使用 shadcn 基础组件构建
3. 保持设计语言一致
- 遵循 shadcn 的设计模式
- 使用语义化变体(default、outline、destructive、ghost、link、secondary)
- 保持间距比例一致
- 遵循 shadcn 的排版层级
4. 不创建自定义 UI 组件
- 不要创建自定义按钮、输入框、卡片等
- 使用 shadcn 组件,或使用 shadcn 基础组件构建
- 例外:业务逻辑组件(非 UI 基础组件)
5. 优先考虑无障碍性
- shadcn 使用 Radix UI(默认支持无障碍性)
- 不要覆盖无障碍功能
- 使用键盘导航和屏幕阅读器进行测试
应避免的反模式
绝不要这样做:
❌ 硬编码颜色
// WRONG
<div style={{ backgroundColor: '#3b82f6' }}>
// RIGHT
<div className="bg-primary">
❌ 硬编码间距
// WRONG
<div style={{ padding: '20px', margin: '10px' }}>
// RIGHT
<div className="p-5 m-2.5">
❌ 为 UI 基础组件创建自定义样式组件
// WRONG
const CustomButton = styled.button`
background: #3b82f6;
padding: 8px 16px;
border-radius: 6px;
`
// RIGHT
import { Button } from '@/components/ui/button'
❌ 内联样式
// WRONG
<div style={{ color: 'red', fontSize: '14px' }}>
// RIGHT
<div className="text-destructive text-sm">
❌ 硬编码字体
// WRONG
<h1 style={{ fontFamily: 'Montserrat' }}>
// RIGHT
<h1 className="font-sans text-4xl font-bold">
❌ 表情符号图标(请改用 Lucide React 图标)
// WRONG
<span>❌ Delete</span>
// RIGHT
import { X } from 'lucide-react'
<Button variant="destructive">
<X className="mr-2 h-4 w-4" />
Delete
</Button>
❌ 任意 CSS 值
// WRONG
<div className="text-[#ff0000]">
// RIGHT
<div className="text-destructive">
最佳实践
✅ 使用语义化颜色名称
// Use semantic CSS variable names
bg-background
text-foreground
bg-primary
text-primary-foreground
bg-secondary
text-muted-foreground
border-border
✅ 使用 Tailwind 间距比例
// Consistent spacing using Tailwind
p-2, p-4, p-6, p-8 // padding
m-2, m-4, m-6, m-8 // margin
gap-2, gap-4 // flex/grid gap
✅ 组合组件
// Build complex UIs by composing shadcn components
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
✅ 使用 MCP 进行发现
// Before building, ask MCP:
// "What shadcn component should I use for [use case]?"
// "Show me examples of shadcn [component]"
✅ 通过组合扩展
// Create higher-level components that compose shadcn
export function FeatureCard({ feature }: { feature: Feature }) {
return (
<Card>
<CardHeader>
<CardTitle>{feature.title}</CardTitle>
</CardHeader>
<CardContent>
<p className="text-muted-foreground">{feature.description}</p>
<Button className="mt-4">Learn More</Button>
</CardContent>
</Card>
)
}
参考文件
特定框架迁移:
组件与样式:
响应式设计与无障碍性:
- 响应式设计模式指南 ⭐ 新增
- 无障碍最佳实践(WCAG 2.1) ⭐ 新增
组件模板示例:
- 响应式导航 - 移动端/平板/桌面端导航模式 ⭐ 新增
- 响应式数据表格 - 移动端显示卡片视图,桌面端显示表格 ⭐ 新增
- 响应式仪表板 - 包含统计数据和图表的响应式网格布局 ⭐ 新增
- 复杂多步骤表单 - 表单验证、文件上传、条件字段 ⭐ 新增
- 功能卡片示例 - 基本的 shadcn 组件组合
- 用户个人资料示例 - 头像、徽章和布局模式
脚本:
./scripts/analyze-codebase.py- 自动分析代码库./scripts/detect-hardcoded-values.sh- 查找反模式./scripts/init-nextjs-shadcn.sh- 初始化项目./scripts/generate-migration-report.py- 生成迁移报告
官方文档:
- shadcn/ui:https://ui.shadcn.com
- Next.js:https://nextjs.org/docs
- Tailwind CSS:https://tailwindcss.com/docs
- Radix UI:https://www.radix-ui.com
- WCAG 2.1 指南:https://www.w3.org/WAI/WCAG21/quickref/
新项目快速入门
如果要创建新的 Next.js 应用(而非进行迁移):
-
初始化
bash ./scripts/init-nextjs-shadcn.sh my-app -
检查 MCP 访问权限
npx shadcn@latest mcp init --client claude -
安装组件
- 使用 MCP 查找所需组件
- 使用
npx shadcn@latest add [component]安装
-
按照最佳实践构建
- 仅使用 CSS 变量
- 组合 shadcn 组件
- 遵循上述设计原则
概述
此技能可系统地将前端迁移至 Next.js + shadcn/ui,并严格遵循设计原则:
- 自动分析现有代码库
- 系统化批量转换(每次处理 5-10 个组件)
- 零容忍硬编码值(仅使用 CSS 变量)
- 集成 MCP,用于发现 shadcn 组件
- 支持多种框架(React、Vue、Angular、原生 JS)
- 全面验证(测试、无障碍性、性能)
**结果:**符合 shadcn/ui 最佳实践的生产级 Next.js 应用,拥有一致的设计系统、完整的深色模式支持,且没有反模式。