fe-stack
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFrontend Tech Stack Convention
前端技术栈规范
기술스택
技术栈
| 항목 | 선택 |
|---|---|
| 언어 | TypeScript 5+ (strict mode) |
| UI 프레임워크 | React 19+ |
| 메타 프레임워크 | Next.js 16+ (App Router) |
| UI 컴포넌트 | shadcn/ui + Radix UI |
| 스타일링 | Tailwind CSS v4 |
| 빌드 도구 | Vite |
| 테스트 | Vitest + React Testing Library |
| 패키지 매니저 | pnpm |
| 린팅 | ESLint + Prettier |
| 类别 | 选型 |
|---|---|
| 编程语言 | TypeScript 5+ (strict mode) |
| UI框架 | React 19+ |
| 元框架 | Next.js 16+ (App Router) |
| UI组件库 | shadcn/ui + Radix UI |
| 样式方案 | Tailwind CSS v4 |
| 构建工具 | Vite |
| 测试工具 | Vitest + React Testing Library |
| 包管理器 | pnpm |
| 代码检查与格式化 | ESLint + Prettier |
프로젝트 구조 (Next.js App Router)
项目结构 (Next.js App Router)
src/
├── app/ # App Router 라우트
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home page
│ ├── globals.css # Global styles (Tailwind)
│ ├── (auth)/ # Route group
│ │ ├── login/page.tsx
│ │ └── signup/page.tsx
│ └── api/ # API Route Handlers
│ └── [resource]/route.ts
├── components/
│ ├── ui/ # shadcn/ui 컴포넌트 (자동 생성)
│ ├── common/ # 공용 컴포넌트
│ └── [feature]/ # 기능별 컴포넌트
├── hooks/ # 커스텀 훅
├── lib/ # 유틸리티, 헬퍼
│ ├── utils.ts # cn() 등 공용 유틸
│ └── api.ts # API 클라이언트
├── types/ # 전역 타입 정의
├── stores/ # 상태 관리 (Zustand)
├── constants/ # 상수 정의
└── __tests__/ # 테스트 파일 (co-location 권장)src/
├── app/ # App Router 路由
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home page
│ ├── globals.css # Global styles (Tailwind)
│ ├── (auth)/ # 路由分组
│ │ ├── login/page.tsx
│ │ └── signup/page.tsx
│ └── api/ # API Route Handlers
├── components/
│ ├── ui/ # shadcn/ui 组件(自动生成)
│ ├── common/ # 通用组件
│ └── [feature]/ # 按功能划分的组件
├── hooks/ # 自定义Hook
├── lib/ # 工具函数、辅助方法
│ ├── utils.ts # cn() 等通用工具
│ └── api.ts # API 客户端
├── types/ # 全局类型定义
├── stores/ # 状态管理(Zustand)
├── constants/ # 常量定义
└── __tests__/ # 测试文件(推荐就近放置)TypeScript 컨벤션
TypeScript 规范
- 필수
strict: true - 로 객체 타입 정의 (확장 가능),
interface은 유니온/인터섹션에 사용type - 사용 금지 →
any+ type guard 사용unknown - 컴포넌트 Props는 로 정의,
interface사용하지 않음React.FC - 타입 단언 최소화, 타입 가드 함수 선호
as - 대신
enum객체 사용as const
typescript
// Props 정의
interface ButtonProps {
variant?: "default" | "destructive" | "outline";
size?: "sm" | "md" | "lg";
children: React.ReactNode;
onClick?: () => void;
}
// as const 패턴
const STATUS = {
IDLE: "idle",
LOADING: "loading",
ERROR: "error",
} as const;
type Status = (typeof STATUS)[keyof typeof STATUS];- 必须开启
strict: true - 使用定义对象类型(支持扩展),
interface用于联合/交叉类型type - 禁止使用,改用
any+ 类型守卫unknown - 组件Props使用定义,不使用
interfaceReact.FC - 尽量减少类型断言,优先使用类型守卫函数
as - 使用对象替代
as constenum
typescript
// Props 定义
interface ButtonProps {
variant?: "default" | "destructive" | "outline";
size?: "sm" | "md" | "lg";
children: React.ReactNode;
onClick?: () => void;
}
// as const 模式
const STATUS = {
IDLE: "idle",
LOADING: "loading",
ERROR: "error",
} as const;
type Status = (typeof STATUS)[keyof typeof STATUS];React 컨벤션
React 规范
- 함수 선언문으로 컴포넌트 정의 (, 화살표 함수도 허용)
function Component() - Props destructuring 사용
- 단일 책임 원칙: 컴포넌트는 하나의 역할만 담당
- 조건부 렌더링: 삼항 연산자 또는 (falsy 값 주의)
&& - 이벤트 핸들러: 네이밍 (예:
handle[Event],handleClick)handleSubmit - 커스텀 훅: 네이밍, 단일 관심사
use[Name] - prop에 index 사용 금지 (안정적인 고유 ID 사용)
key
tsx
function UserCard({ name, email, onEdit }: UserCardProps) {
const handleEditClick = () => onEdit(email);
return (
<Card>
<CardHeader>
<CardTitle>{name}</CardTitle>
</CardHeader>
<CardContent>
<p className="text-muted-foreground">{email}</p>
<Button variant="outline" onClick={handleEditClick}>
Edit
</Button>
</CardContent>
</Card>
);
}- 使用函数声明式定义组件(,箭头函数也可)
function Component() - 使用Props解构
- 单一职责原则:组件仅承担一个职责
- 条件渲染:使用三元运算符或(注意假值陷阱)
&& - 事件处理器:采用命名方式(如:
handle[Event]、handleClick)handleSubmit - 自定义Hook:采用命名方式,遵循单一关注点
use[Name] - 禁止在属性中使用索引,需使用稳定的唯一ID
key
tsx
function UserCard({ name, email, onEdit }: UserCardProps) {
const handleEditClick = () => onEdit(email);
return (
<Card>
<CardHeader>
<CardTitle>{name}</CardTitle>
</CardHeader>
<CardContent>
<p className="text-muted-foreground">{email}</p>
<Button variant="outline" onClick={handleEditClick}>
Edit
</Button>
</CardContent>
</Card>
);
}Next.js App Router 규칙
Next.js App Router 规则
- Server Component 기본, 필요 시 선언
"use client" - 는 가능한 트리의 말단에 배치 (클라이언트 경계 최소화)
"use client" - 데이터 페칭: Server Component에서 로 직접 fetch
async/await - Server Actions: 함수로 폼 처리, 뮤테이션
"use server" - ,
loading.tsx,error.tsx활용not-found.tsx - Metadata: 또는 정적
generateMetadata()객체metadata - Route Handler: ,
GET등 named export 함수POST - 동적 라우트: 폴더,
[param]로 정적 생성generateStaticParams() - Parallel Routes(), Intercepting Routes(
@slot) 적절히 활용(.)
- 默认使用Server Component,必要时声明
"use client" - 应尽可能放在组件树的末端(最小化客户端边界)
"use client" - 数据获取:在Server Component中直接使用进行fetch
async/await - Server Actions:使用函数处理表单、数据变更
"use server" - 使用、
loading.tsx、error.tsx处理状态not-found.tsx - 元数据:使用或静态
generateMetadata()对象metadata - 路由处理器:使用、
GET等具名导出函数POST - 动态路由:使用文件夹,通过
[param]生成静态路由generateStaticParams() - 合理使用Parallel Routes()、Intercepting Routes(
@slot)(.)
shadcn/ui 규칙
shadcn/ui 规则
- 로 컴포넌트 추가
npx shadcn@latest add [component] - 에 생성된 코드를 프로젝트 요구에 맞게 커스터마이즈
components/ui/ - 유틸리티로 조건부 클래스 합성
cn() - Radix UI primitives 기반으로 접근성 내장
- 테마 커스터마이즈는 의 CSS 변수로 관리
globals.css
tsx
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
<Button className={cn("w-full", isActive && "bg-primary")} variant="outline">
Click
</Button>- 使用命令添加组件
npx shadcn@latest add [component] - 根据项目需求自定义中生成的代码
components/ui/ - 使用工具函数组合条件类名
cn() - 基于Radix UI primitives,内置无障碍支持
- 通过中的CSS变量管理主题自定义
globals.css
tsx
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
<Button className={cn("w-full", isActive && "bg-primary")} variant="outline">
Click
</Button>Tailwind CSS v4 규칙
Tailwind CSS v4 规则
- 유틸리티 클래스 우선, 커스텀 CSS 최소화
- 사용 최소화 (컴포넌트 추출 선호)
@apply - 반응형: ,
sm:,md:,lg:,xl:접두사 (mobile-first)2xl: - 다크 모드: 접두사 + CSS 변수 기반 테마
dark: - 또는
clsx(tailwind-merge)로 동적 클래스 합성cn()
- 优先使用工具类,尽量减少自定义CSS
- 尽量减少的使用(优先提取组件)
@apply - 响应式:使用、
sm:、md:、lg:、xl:前缀(移动端优先)2xl: - 深色模式:使用前缀 + 基于CSS变量的主题
dark: - 使用或
clsx(tailwind-merge)组合动态类名cn()
상태 관리
状态管理
- 로컬 상태: ,
useStateuseReducer - 서버 상태: TanStack Query (React Query)
- 전역 클라이언트 상태: Zustand
- URL 상태: ,
useSearchParamsnuqs - 폼 상태: React Hook Form + Zod 유효성 검사
- 本地状态:、
useStateuseReducer - 服务端状态:TanStack Query (React Query)
- 全局客户端状态:Zustand
- URL状态:、
useSearchParamsnuqs - 表单状态:React Hook Form + Zod 校验
파일 네이밍 규칙
文件命名规则
| 대상 | 규칙 | 예시 |
|---|---|---|
| 컴포넌트 | PascalCase | |
| 훅 | camelCase (use 접두사) | |
| 유틸리티 | camelCase | |
| 타입 | PascalCase | |
| 상수 | camelCase 파일, UPPER_SNAKE 변수 | |
| 테스트 | 원본명.test | |
| 페이지 (App Router) | 소문자 폴더 | |
| 对象 | 规则 | 示例 |
|---|---|---|
| 组件 | PascalCase | |
| Hook | 小驼峰(以use为前缀) | |
| 工具函数 | 小驼峰 | |
| 类型定义文件 | PascalCase | |
| 常量文件 | 文件名小驼峰,变量名大写下划线分隔 | |
| 测试文件 | 原文件名.test | |
| 页面(App Router) | 小写文件夹 | |
Import 순서
导入顺序
typescript
// 1. React/Next.js
import { useState } from "react";
import Link from "next/link";
// 2. 서드파티 라이브러리
import { useQuery } from "@tanstack/react-query";
import { z } from "zod";
// 3. 내부 컴포넌트 (shadcn/ui 포함)
import { Button } from "@/components/ui/button";
import { UserCard } from "@/components/user/UserCard";
// 4. 훅, 유틸, 타입
import { useAuth } from "@/hooks/useAuth";
import { cn } from "@/lib/utils";
import type { User } from "@/types";typescript
// 1. React/Next.js
import { useState } from "react";
import Link from "next/link";
// 2. 第三方库
import { useQuery } from "@tanstack/react-query";
import { z } from "zod";
// 3. 内部组件(包含shadcn/ui)
import { Button } from "@/components/ui/button";
import { UserCard } from "@/components/user/UserCard";
// 4. Hook、工具函数、类型
import { useAuth } from "@/hooks/useAuth";
import { cn } from "@/lib/utils";
import type { User } from "@/types";