KS
Killer-Skills

piko-frontend-standards — how to use piko-frontend-standards how to use piko-frontend-standards, piko-frontend-standards vs other coding standards, piko-frontend-standards setup guide, what is piko-frontend-standards, piko-frontend-standards alternative, piko-frontend-standards install, code as documentation examples, page autonomy benefits, single responsibility principle in frontend development

v1.0.0
GitHub

About this Skill

Perfect for Frontend Development Agents needing strict code standards and efficient, self-explanatory code. piko-frontend-standards is a coding standard that adheres to principles such as code as documentation, page autonomy, and single responsibility.

Features

Enforces code as documentation principle for self-explanatory code
Promotes page autonomy with self-contained components, hooks, types, consts, and utils
Implements single responsibility principle for functions, components, and hooks
Favors composition over complexity with slot and hook combinations
Explicitly annotates return types and handles promises with await or void
Utilizes type systems as contracts between modules with discriminated unions

# Core Topics

Babytiann Babytiann
[0]
[0]
Updated: 3/7/2026

Quality Score

Top 5%
54
Excellent
Based on code quality & docs
Installation
SYS Universal Install (Auto-Detect)
Cursor IDE Windsurf IDE VS Code IDE
> npx killer-skills add Babytiann/Piko/piko-frontend-standards

Agent Capability Analysis

The piko-frontend-standards MCP Server by Babytiann is an open-source Categories.community integration for Claude and other AI agents, enabling seamless task automation and capability expansion. Optimized for how to use piko-frontend-standards, piko-frontend-standards vs other coding standards, piko-frontend-standards setup guide.

Ideal Agent Persona

Perfect for Frontend Development Agents needing strict code standards and efficient, self-explanatory code.

Core Value

Empowers agents to write efficient frontend code using a strict coding philosophy, promoting code as documentation, page autonomy, and single responsibility, with explicit type annotations and composition over complexity using Slot and Hook combinations.

Capabilities Granted for piko-frontend-standards MCP Server

Enforcing code as documentation principles for improved readability
Implementing page autonomy for scalable and maintainable frontend applications
Optimizing codebase with single responsibility and composition over complexity principles

! Prerequisites & Limits

  • Requires adherence to strict coding standards
  • May not be suitable for rapid prototyping or proof-of-concept development
  • Explicit type annotations and contract-based typing may add initial development overhead
Project
SKILL.md
18.6 KB
.cursorrules
1.2 KB
package.json
240 B
Ready
UTF-8

# Tags

[No tags]
SKILL.md
Readonly

Piko Frontend Code Standards

严格派:代码即文档,每一行都有存在的理由。

Core Philosophy

  1. Code as Documentation — 代码即文档,命名自解释,拒绝冗余注释
  2. Page Autonomy — 每个页面是自包含单元,拥有自己的 components/hooks/types/consts/utils
  3. Single Responsibility — 一个函数/组件/hook 只做一件事
  4. Composition over Complexity — Slot 组合 > 巨型组件,Hook 组合 > 万能 Hook
  5. Explicit over Implicit — 所有返回类型显式标注,所有 Promise 要么 await 要么 void
  6. Type as Contract — 类型系统是模块间的契约,用判别联合而非松散可选字段
  7. Fail Fast, Fail Loud — 纯函数映射错误类型,不在 hook 里硬编码错误逻辑

Comments: Less is More

MUST:  用清晰的函数名/变量名/类型名替代注释
MUST:  复杂算法或非直觉的业务规则才需要注释
MUST:  注释解释 WHY,不解释 WHAT (代码本身说明 what)
NEVER: 函数签名上方加 JSDoc 复述参数名和类型 — TypeScript 已经表达了
NEVER: 注释掉的代码 — 直接删除,git 有历史
NEVER: 分隔线注释 (// ────────) — 用空行和函数拆分表达结构
NEVER: "显而易见"的注释 (// 设置 loading 为 true → setIsLoading(true))

Architecture: Page-Autonomous Structure

frontend/
├── app/                           # Expo Router 路由 (Screen 层)
│   ├── _layout.tsx
│   ├── (tabs)/
│   │   ├── index.tsx              # → 编排 pages/home 的内容
│   │   ├── ai/index.tsx
│   │   └── profile/index.tsx
│   └── chat/[id].tsx
│
├── pages/                         # 页面业务单元 (每个页面自包含)
│   ├── home/
│   │   ├── components/            # 页面私有组件
│   │   ├── hooks/                 # 页面私有 hooks
│   │   ├── types/                 # 页面私有类型
│   │   ├── consts/                # 页面私有常量
│   │   └── utils/                 # 页面私有工具函数
│   ├── profile/
│   │   ├── components/
│   │   ├── hooks/
│   │   └── types/
│   └── chat/
│       ├── components/
│       ├── hooks/
│       └── types/
│
├── common/                        # 跨页面共享
│   ├── components/
│   │   ├── page-loading/          # 通用加载
│   │   ├── page-status-view/      # 通用错误/空态 + getPageErrorType()
│   │   ├── biz/                   # 业务级共享组件
│   │   └── product-card/          # 可复用卡片 (Slot 组合)
│   ├── hooks/                     # 通用 hooks (useAuth, useSafeArea)
│   │   └── index.ts              # Barrel re-export
│   ├── typings/                   # 共享类型定义
│   └── consts/                    # 全局常量
│
├── services/                      # API client + 页面级数据获取
│   ├── api-client.ts             # 底层请求封装 (post, postSafe, postDirect)
│   ├── home.ts                   # 首页数据获取
│   ├── chat.ts                   # 聊天数据获取
│   ├── profile.ts                # 个人资料数据获取
│   └── telegram.ts               # Telegram 认证 & 消息 API
│
├── lib/                           # 框架级配置(如认证客户端)
│   └── auth-client.ts            # Better Auth 客户端 (createAuthClient),session/Cookie 与后端一致
│
├── contexts/                      # Context 定义
└── utils/                         # 全局工具函数

关键原则

MUST:  页面私有代码放 pages/{page}/ 下,不放 common/
MUST:  跨 2 个以上页面复用的代码提升到 common/
MUST:  数据获取逻辑放 services/ (按页面分文件),不内联在组件中
MUST:  common/hooks/index.ts barrel re-export 所有公共 hooks
MUST:  页面私有工具函数放 pages/{page}/utils/,一个文件一个主函数
MUST:  utils/ 文件名 = 主函数名 (kebab-case),如 calc-column-widths.ts
MUST:  utils/index.ts barrel re-export 所有工具函数
MUST:  utils/ 仅含纯函数 — 不含 hooks / 组件 / 副作用
NEVER: 工具函数内联在组件文件中 — 提取到 utils/
NEVER: 页面级 hooks/components 目录创建 barrel index.ts — 直接 import 具体文件
NEVER: 页面 A 直接 import 页面 B 的私有模块
NEVER: common/ 下的代码 import pages/ 下的代码 (依赖方向: pages → common)

Component Patterns

分类与位置

类型位置职责
Screenapp/路由入口,编排页面组件
Page Componentpages/{page}/components/页面私有 UI
Biz Sharedcommon/components/biz/跨页面业务组件
Base Sharedcommon/components/通用 UI,零业务

规则

MUST:  Props 接口命名: 文件内用 Props,跨文件导出用 {ComponentName}Props
MUST:  显式返回类型: (props: Props): ReactNode => { ... }
MUST:  页面内组件用页面前缀: Chat 页的组件用 Chat 前缀 (ChatBubble, ChatInput)
MUST:  条件渲染统一三元: {condition ? <X /> : null}
MUST:  空状态统一 return null
MUST:  Slot 组合: 通过 leftArea/title/footer 等 ReactNode props 组合复杂布局
MUST:  多组件文件 — 主组件 index.tsx + 子组件各自独立文件,放同名文件夹下
MUST:  子组件文件名 = 组件名 (kebab-case),如 waiting-indicator.tsx
ALLOW: 极简渲染辅助 (无 hooks、1-3 行 JSX) — 可用箭头函数常量留在同文件
MUST:  组件文件内的非公用辅助函数使用箭头函数常量 (const fn = (...): T => { ... }),不用 function 声明
NEVER: function 声明式定义多个组件在同一文件
NEVER: 超过 150 行的组件 — 拆分,依据具体情况拆分,如果真的要这么多,那就不拆了
NEVER: Props 透传超过 2 层 — 用 Context

Slot 组合示例

typescript
1interface Props<T> { 2 data: T; 3 leftArea?: ReactNode; 4 title?: ReactNode; 5 subtitle?: ReactNode; 6 operationArea?: ReactNode; 7 onPress?: (data: T) => void; 8} 9 10export default function CardContainer<T>({ data, leftArea, title, subtitle, operationArea, onPress }: Props<T>): ReactNode { 11 return ( 12 <XStack onPress={() => onPress?.(data)}> 13 {leftArea ? <YStack flexShrink={0}>{leftArea}</YStack> : null} 14 <YStack flex={1}> 15 {title ? title : null} 16 {subtitle ? subtitle : null} 17 {operationArea ? operationArea : null} 18 </YStack> 19 </XStack> 20 ); 21}

Hook Taxonomy

前置规则: 禁止空壳 re-export

NEVER: 创建只做 re-export 的 hook 文件 (如 export { useX } from 'lib')
       → 直接从源库导入,空壳文件是死代码的温床
ONLY:  当你封装了自定义逻辑时,才值得创建 hook 文件

useCallback / useMemo 使用规则

NEVER: 默认给事件处理函数套 useCallback,给计算结果套 useMemo — 大多数场景没有收益
ONLY:  useCallback: 回调传给 React.memo 子组件,或作为 useEffect/useMemo 的依赖
ONLY:  useMemo: 计算确实昂贵 (大数组遍历、复杂格式化),或结果作为 useEffect 的依赖需要稳定引用
MUST:  简单赋值/三元/条件判断直接写,不套 useMemo
MUST:  组件内部的事件处理函数直接写普通函数,不套 useCallback

Hooks 严格分三类,每类有明确的约束:

① 数据 Hook (Data Hook)

职责:获取数据 + 管理 loading/error 状态。返回结构化对象。

MUST:  返回命名字段: { isLoading, errorType, data, handleRetry, handleRefresh }
MUST:  错误映射使用纯函数 getPageErrorType(),不在 hook 中硬编码
MUST:  最多 1 个 useEffect (初始加载)
MUST:  返回类型显式定义为 interface
MUST:  使用 state trigger (fetchKey) + useEffect 重新触发请求,不用 useCallback 包裹请求逻辑
MUST:  useEffect cleanup 设置 cancelled 标记防止竞态更新
NEVER: useCallback 包裹网络请求函数 — 请求只在 useEffect 内发起

标准 Data Hook 模式

typescript
1// 简单模式: 加载 + 重试 2const [fetchKey, setFetchKey] = useState<number>(0); 3 4useEffect(() => { 5 let cancelled = false; 6 setIsLoading(true); 7 setErrorType(undefined); 8 9 async function load(): Promise<void> { 10 try { 11 const response = await fetchXxxPage(); 12 if (cancelled) return; 13 const mappedError = getPageErrorType(response); 14 if (mappedError) { 15 setErrorType(mappedError); 16 setData(null); 17 } else { 18 setData(response.data ?? null); 19 } 20 } catch { 21 if (cancelled) return; 22 setErrorType(PageErrorType.NETWORK); 23 setData(null); 24 } finally { 25 if (!cancelled) setIsLoading(false); 26 } 27 } 28 29 void load(); 30 return () => { 31 cancelled = true; 32 }; 33}, [fetchKey]); // + 其他依赖如 session 34 35const handleRetry = (): void => { 36 setFetchKey((k) => k + 1); 37};

② 派生 Hook (Derived Hook)

职责:纯计算/数据转换,零副作用。只用 useMemo

MUST:  只使用 useMemo,不使用 useEffect / useState
MUST:  纯函数语义: 相同输入永远相同输出
MUST:  命名体现数据来源: useDataFromQuery, useFormattedPrice

③ 副作用 Hook (Effect Hook)

职责:管理单一副作用 (事件监听、定时器、性能埋点)。

MUST:  只有 1 个 useEffect
MUST:  useRef 保存最新回调 (防止闭包过期)
MUST:  cleanup 函数清理所有副作用
MUST:  返回类型为 void (不返回状态)

组合

typescript
1// pages/chat/hooks/useChatPageData.ts — 数据 hook (单一 effect) 2// pages/chat/hooks/useChatPolling.ts — 副作用 hook (单一 effect) 3// 在 Screen 层组合: 4const pageData = useChatPageData(chatId); 5useChatPolling(pageData.silentRefresh, pollingInterval);

详见 STANDARDS.mdPATTERNS.md

Type Safety

MUST:  所有函数参数 + 返回值显式标注类型
MUST:  组件返回类型标注 ReactNode
MUST:  Hook 返回类型定义为 interface (不用内联对象类型)
MUST:  Context 用判别联合 (discriminated union) 区分场景
MUST:  error 使用 enum PageErrorType,不用 string
MUST:  API 响应用 type guard 验证,不用 as T
MUST:  不等待的 Promise 用 void 标记: void doSomething()
NEVER: any — 用 unknown + type guard
NEVER: as T 类型断言
NEVER: ! 非空断言

API/IDL 接口类型(蛇形命名)

凡用于描述接口契约的类型(HTTP 请求体、响应体、SSE 事件 payload 等),其字段名必须使用 snake_case,与后端、第三方 API 的 JSON 契约保持一致,便于跨语言/跨端对齐。

MUST:  请求体/响应体/SSE 事件等 IDL 类型的属性名使用 snake_case (如 conversation_id, header_title)
MUST:  前端读取 API 响应、组装请求体、解析 SSE 时使用与类型一致的 snake_case 键
NEVER: 在接口契约类型中使用 camelCase 字段名

仅在前端或后端内部使用的类型(如组件 Props、Hook 返回类型、内部状态)仍按「代码」命名规范使用 camelCase。

判别联合 Context 示例

typescript
1interface ChatDirectContext { 2 scene: 'direct'; 3 peerId: string; 4 getLogParams: () => DirectLogParams; 5} 6 7interface ChatGroupContext { 8 scene: 'group'; 9 groupId: string; 10 memberCount: number; 11 getLogParams: () => GroupLogParams; 12} 13 14type ChatPageContext = ChatDirectContext | ChatGroupContext;

Error Handling

MUST:  纯函数映射错误: getPageErrorType(response) => PageErrorType | undefined
MUST:  PageErrorType 使用 enum (DEFAULT, NETWORK, AUTH, EMPTY)
MUST:  数据 Hook 中调用 getPageErrorType 设置错误状态
MUST:  所有 async 必须 try/catch 或 .catch()
MUST:  不等待的 async 调用加 void 前缀: void fetchData()
NEVER: catch(e) {} 空 catch
NEVER: silentLoad 无 catch — 静默操作也要 console.error

标准错误流

API 响应 → getPageErrorType(resp) → PageErrorType | undefined
                                        ↓
                              undefined = 成功,继续处理
                              PageErrorType = 设置错误状态
                                        ↓
                              Screen: <PageStatusView errorType={errorType} onRetry={handleRetry} />

Style System: Tamagui-First

核心规则

MUST:  使用 Tamagui 组件 (XStack, YStack, View, Text) 替代 RN 原生组件
MUST:  布局用 Tamagui props (bg, px, py, gap, flex, borderRadius, mt, mb, pl 等)
MUST:  颜色只用 theme tokens ($color, $blue9, $gray4, $background)
MUST:  间距只用 size tokens ($1, $2, $3, $4)
MUST:  交互用 Tamagui 的 pressStyle + onPress,不用 RN Pressable/TouchableOpacity
MUST:  非 Tamagui 组件 (如 Ionicons) 的颜色用 useTheme() + theme.xxx.val
NEVER: 从 'react-native' 导入 View / Text — 从 'tamagui' 导入
NEVER: useMemo 构造 style 对象 — 把样式直接写成 Tamagui props
NEVER: className / Tailwind
NEVER: 硬编码颜色 (#ffffff, rgba(...))
ALLOW: style prop — 仅 Tamagui 不支持的属性 (borderRadius 部分值、alignItems 等)

正确 vs 错误示例

typescript
1// BAD: RN 组件 + useMemo style 对象 2import { View, Text, Pressable } from 'react-native'; 3const styles = useMemo(() => ({ 4 container: { padding: 12, backgroundColor: theme.blue2.val, borderRadius: 12 }, 5 title: { fontSize: 14, fontWeight: '600', color: theme.blue11.val }, 6}), [themeName]); 7return ( 8 <Pressable onPress={handlePress}> 9 <View style={styles.container}> 10 <Text style={styles.title}>标题</Text> 11 </View> 12 </Pressable> 13); 14 15// GOOD: Tamagui 组件 + inline props 16import { YStack, Text } from 'tamagui'; 17return ( 18 <YStack 19 bg="$blue2" 20 px="$3" 21 py="$2.5" 22 borderWidth={1} 23 borderColor="$blue7" 24 pressStyle={{ opacity: 0.8 }} 25 onPress={handlePress} 26 style={{ borderRadius: 12 }} 27 > 28 <Text fontSize={14} fontWeight="600" color="$blue11">标题</Text> 29 </YStack> 30);

Naming Conventions

文件

组件:     kebab-case.tsx     (chat-bubble.tsx, page-loading.tsx)
Hook:     camelCase.ts       (useFetchData.ts, usePolling.ts)
Service:  camelCase.ts       (chatService.ts, profileService.ts)
Type:     index.ts (在 types/ 目录下)
常量:     index.ts (在 consts/ 目录下)
工具函数: kebab-case.ts      (calc-column-widths.ts, sanitize-streaming-markdown.ts)
目录:     kebab-case/        (page-status-view/, operation-button/)
Barrel:   common/hooks/index.ts 和 pages/{page}/utils/index.ts 需要 barrel re-export

代码

组件名:      PascalCase + 页面前缀    ChatBubble, ChatInput, ProfileCard
Hook:        use 前缀                useFetchData, usePolling, useAuth
常量:        UPPER_SNAKE_CASE        TAB_BAR_HEIGHT, POLLING_INTERVAL
Enum:        PascalCase              PageErrorType, ChatScene
函数:        camelCase + 动词        fetchChatList, getPageErrorType, handleRetry
布尔:        is/has/should 前缀      isLoading, hasMedia, shouldRefresh
回调 Props:  on 前缀                 onPress, onRetry, onBind
处理函数:    handle 前缀             handleBind, handleRetry
返回类型:    显式标注                (): ReactNode, (): void, (): Promise<void>

Import Organization

typescript
1// 1. React / React Native 核心 2import { useState, useCallback } from 'react'; 3import { Alert } from 'react-native'; 4 5// 2. 第三方框架 6import { useRouter } from 'expo-router'; 7import { YStack, Text } from 'tamagui'; 8 9// 3. 项目 common/ (shared) 10import type { ProfilePageData } from '@/common/typings/profile'; 11import { useAuth } from '@/common/hooks'; 12import PageLoading from '@/common/components/page-loading'; 13import { getPageErrorType } from '@/common/components/page-status-view'; 14 15// 4. 项目 services/ (数据获取) 16import { fetchProfilePage } from '@/services/profile'; 17 18// 5. 页面相对路径 (同页面内) 19import { POLLING_INTERVAL } from '../consts'; 20import type { ChatLogParams } from '../types'; 21import ChatBubble from './chat-bubble';
MUST:  type-only imports 使用 import type { X }
MUST:  组间保留空行
MUST:  同组内按字母排序
MUST:  common/hooks 用 barrel import: from '@/common/hooks'

认证 (Better Auth)

Piko 统一使用 Better Auth 做登录与鉴权。

MUST:  登录、session、OAuth(如 Apple 登录)使用 frontend/lib/auth-client.ts 的 createAuthClient 实例
MUST:  需要带登录态请求时,用 authClient.getSession() / getCookie() 等注入;若在 fetch 里手动设置 Cookie,使用 credentials: 'omit'(与 Better Auth 文档一致)
MUST:  鉴权/登录相关逻辑以 Better Auth 文档与项目 PRD(如 docs/PRD-Apple-Login-Better-Auth-Alignment.md)为准
NEVER: 引入或教学其他认证库(如 Next-Auth)替代 Better Auth

依赖管理 (Dependency Management)

NEVER: 通过直接编辑 package.json 添加或删除依赖
MUST:  使用包管理器官方命令添加/删除依赖(与本项目一致)
       例如: pnpm add <pkg> / pnpm add -D <pkg>、pnpm remove <pkg>
       或: npm install <pkg>、yarn add <pkg>(以项目根目录 package.json 或文档为准)
MUST:  添加依赖前确认当前项目使用的包管理器(看 lockfile: pnpm-lock.yaml / package-lock.json / yarn.lock)

无论何时需要新增或移除依赖,都必须通过终端执行官方命令,不得手改 package.json

Enforcement

写代码时自动检查:

  1. 页面私有代码是否放在 pages/{page}/ 下?
  2. 组件是否超过 150 行?→ 拆分,依据具体情况拆分,如果真的要这么多,那就不拆了
  3. Hook 是否属于明确的分类 (数据/派生/副作用)?
  4. Hook 是否有多个 useEffect?→ 拆分
  5. 返回类型是否显式标注?→ 补充 ReactNode / void
  6. 是否有 any/as/! ?→ type guard
  7. error 是否用 enum?→ 不用 string
  8. 不等待的 Promise 是否加了 void?
  9. 样式是否用 Tamagui token?→ 不用 className/硬编码
  10. import 是否按规范分组?
  11. 新增/删除依赖是否通过包管理器命令?→ 禁止直接编辑 package.json
  12. 登录/鉴权相关是否使用 Better Auth(auth-client、credentials: 'omit' 当手动设 Cookie)?→ 见「认证 (Better Auth)」节

References

Related Skills

Looking for an alternative to piko-frontend-standards or building a Categories.community AI Agent? Explore these related open-source MCP Servers.

View All

widget-generator

Logo of f
f

widget-generator is an open-source AI agent skill for creating widget plugins that are injected into prompt feeds on prompts.chat. It supports two rendering modes: standard prompt widgets using default PromptCard styling and custom render widgets built as full React components.

149.6k
0
Design

chat-sdk

Logo of lobehub
lobehub

chat-sdk is a unified TypeScript SDK for building chat bots across multiple platforms, providing a single interface for deploying bot logic.

73.0k
0
Communication

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
Communication

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
Communication