OA0 = Omni AI 0
OA0 是一个探索 AI 的论坛
现在注册
已注册用户请  登录
OA0  ›  技能包  ›  senior-frontend: 针对 React 与 Next.js 的前端开发专家技能

senior-frontend: 针对 React 与 Next.js 的前端开发专家技能

 
  txt ·  2026-02-01 22:05:01 · 3 次点击  · 0 条评论  

name: senior-frontend
description: 适用于 React、Next.js、TypeScript 和 Tailwind CSS 应用的前端开发技能。用于构建 React 组件、优化 Next.js 性能、分析打包体积、搭建前端项目、实现无障碍访问或评审前端代码质量。


高级前端开发

针对 React/Next.js 应用的前端开发模式、性能优化与自动化工具。

目录


项目脚手架

使用 TypeScript、Tailwind CSS 及最佳实践配置,生成新的 Next.js 或 React 项目。

工作流:创建新前端项目

  1. 使用项目名称和模板运行脚手架工具:
    bash python scripts/frontend_scaffolder.py my-app --template nextjs

  2. 添加可选功能(认证、API、表单、测试、Storybook):
    bash python scripts/frontend_scaffolder.py dashboard --template nextjs --features auth,api

  3. 进入项目目录并安装依赖:
    bash cd my-app && npm install

  4. 启动开发服务器:
    bash npm run dev

脚手架选项

选项 描述
--template nextjs Next.js 14+,包含 App Router 和 Server Components
--template react React + Vite,包含 TypeScript
--features auth 添加 NextAuth.js 认证
--features api 添加 React Query + API 客户端
--features forms 添加 React Hook Form + Zod 验证
--features testing 添加 Vitest + Testing Library
--dry-run 预览文件而不实际创建

生成的项目结构 (Next.js)

my-app/
├── app/
│   ├── layout.tsx        # 根布局(包含字体)
│   ├── page.tsx          # 首页
│   ├── globals.css       # Tailwind + CSS 变量
│   └── api/health/route.ts
├── components/
│   ├── ui/               # Button、Input、Card 等基础组件
│   └── layout/           # Header、Footer、Sidebar 等布局组件
├── hooks/                # useDebounce、useLocalStorage 等自定义 Hook
├── lib/                  # 工具函数(如 cn)、常量
├── types/                # TypeScript 接口定义
├── tailwind.config.ts
├── next.config.js
└── package.json

组件生成

生成包含 TypeScript 类型、测试和 Storybook 故事的 React 组件。

工作流:创建新组件

  1. 生成客户端组件:
    bash python scripts/component_generator.py Button --dir src/components/ui

  2. 生成服务端组件:
    bash python scripts/component_generator.py ProductCard --type server

  3. 生成包含测试和故事文件的组件:
    bash python scripts/component_generator.py UserProfile --with-test --with-story

  4. 生成自定义 Hook:
    bash python scripts/component_generator.py FormValidation --type hook

生成器选项

选项 描述
--type client 包含 'use client' 的客户端组件(默认)
--type server 异步服务端组件
--type hook 自定义 React Hook
--with-test 包含测试文件
--with-story 包含 Storybook 故事文件
--flat 直接在输出目录创建,不生成子目录
--dry-run 预览而不创建文件

生成的组件示例

'use client';

import { useState } from 'react';
import { cn } from '@/lib/utils';

interface ButtonProps {
  className?: string;
  children?: React.ReactNode;
}

export function Button({ className, children }: ButtonProps) {
  return (
    <div className={cn('', className)}>
      {children}
    </div>
  );
}

打包分析

分析 package.json 和项目结构,寻找打包优化的机会。

工作流:优化打包体积

  1. 在项目上运行分析器:
    bash python scripts/bundle_analyzer.py /path/to/project

  2. 查看健康评分和问题:
    ```
    打包健康评分: 75/100 (C)

    过重依赖:
    moment (290KB)
    替代方案: date-fns (12KB) 或 dayjs (2KB)

    lodash (71KB)
    替代方案: 使用支持 Tree Shaking 的 lodash-es
    ```

  3. 应用推荐的修复方案,替换过重的依赖。

  4. 使用详细模式重新运行,检查导入模式:
    bash python scripts/bundle_analyzer.py . --verbose

打包评分解读

分数 等级 建议操作
90-100 A 打包已充分优化
80-89 B 存在少量优化空间
70-79 C 建议替换过重依赖
60-69 D 存在多个需要关注的问题
0-59 F 存在严重的打包体积问题

常见过重依赖检测

分析器会识别以下常见的过重包:

大小 替代方案
moment 290KB date-fns (12KB) 或 dayjs (2KB)
lodash 71KB 使用支持 Tree Shaking 的 lodash-es
axios 14KB 原生 fetch 或 ky (3KB)
jquery 87KB 原生 DOM API
@mui/material 较大 shadcn/ui 或 Radix UI

React 模式

参考:references/react_patterns.md

复合组件

在相关组件间共享状态:

const Tabs = ({ children }) => {
  const [active, setActive] = useState(0);
  return (
    <TabsContext.Provider value={{ active, setActive }}>
      {children}
    </TabsContext.Provider>
  );
};

Tabs.List = TabList;
Tabs.Panel = TabPanel;

// 使用
<Tabs>
  <Tabs.List>
    <Tabs.Tab>标签一</Tabs.Tab>
    <Tabs.Tab>标签二</Tabs.Tab>
  </Tabs.List>
  <Tabs.Panel>内容一</Tabs.Panel>
  <Tabs.Panel>内容二</Tabs.Panel>
</Tabs>

自定义 Hook

提取可复用的逻辑:

function useDebounce<T>(value: T, delay = 500): T {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedValue(value), delay);
    return () => clearTimeout(timer);
  }, [value, delay]);

  return debouncedValue;
}

// 使用
const debouncedSearch = useDebounce(searchTerm, 300);

Render Props

共享渲染逻辑:

function DataFetcher({ url, render }) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch(url).then(r => r.json()).then(setData).finally(() => setLoading(false));
  }, [url]);

  return render({ data, loading });
}

// 使用
<DataFetcher
  url="/api/users"
  render={({ data, loading }) =>
    loading ? <Spinner /> : <UserList users={data} />
  }
/>

Next.js 优化

参考:references/nextjs_optimization_guide.md

服务端组件 vs 客户端组件

默认使用服务端组件。仅在需要以下功能时添加 'use client':
- 事件处理器(onClick、onChange)
- 状态(useState、useReducer)
- 副作用(useEffect)
- 浏览器 API

// 服务端组件(默认)- 无 'use client'
async function ProductPage({ params }) {
  const product = await getProduct(params.id);  // 服务端获取数据

  return (
    <div>
      <h1>{product.name}</h1>
      <AddToCartButton productId={product.id} />  {/* 客户端组件 */}
    </div>
  );
}

// 客户端组件
'use client';
function AddToCartButton({ productId }) {
  const [adding, setAdding] = useState(false);
  return <button onClick={() => addToCart(productId)}>加入购物车</button>;
}

图片优化

import Image from 'next/image';

// 首屏图片 - 立即加载
<Image
  src="/hero.jpg"
  alt="主图"
  width={1200}
  height={600}
  priority
/>

// 响应式图片,使用 fill 属性
<div className="relative aspect-video">
  <Image
    src="/product.jpg"
    alt="产品图"
    fill
    sizes="(max-width: 768px) 100vw, 50vw"
    className="object-cover"
  />
</div>

数据获取模式

// 并行获取
async function Dashboard() {
  const [user, stats] = await Promise.all([
    getUser(),
    getStats()
  ]);
  return <div>...</div>;
}

// 使用 Suspense 进行流式渲染
async function ProductPage({ params }) {
  return (
    <div>
      <ProductDetails id={params.id} />
      <Suspense fallback={<ReviewsSkeleton />}>
        <Reviews productId={params.id} />
      </Suspense>
    </div>
  );
}

无障碍与测试

参考:references/frontend_best_practices.md

无障碍检查清单

  1. 语义化 HTML:使用正确的元素(<button><nav><main>
  2. 键盘导航:所有交互元素均可聚焦
  3. ARIA 标签:为图标和复杂控件提供标签
  4. 颜色对比度:普通文本至少达到 4.5:1
  5. 焦点指示器:提供可见的焦点状态
// 无障碍按钮
<button
  type="button"
  aria-label="关闭对话框"
  onClick={onClose}
  className="focus-visible:ring-2 focus-visible:ring-blue-500"
>
  <XIcon aria-hidden="true" />
</button>

// 为键盘用户提供的跳过链接
<a href="#main-content" className="sr-only focus:not-sr-only">
  跳转到主要内容
</a>

测试策略

// 使用 React Testing Library 进行组件测试
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

test('点击按钮触发操作', async () => {
  const onClick = vi.fn();
  render(<Button onClick={onClick}>点击我</Button>);

  await userEvent.click(screen.getByRole('button'));
  expect(onClick).toHaveBeenCalledTimes(1);
});

// 测试无障碍性
test('对话框具有无障碍性', async () => {
  render(<Dialog open={true} title="确认" />);

  expect(screen.getByRole('dialog')).toBeInTheDocument();
  expect(screen.getByRole('dialog')).toHaveAttribute('aria-labelledby');
});

快速参考

常见 Next.js 配置

// next.config.js
const nextConfig = {
  images: {
    remotePatterns: [{ hostname: 'cdn.example.com' }],
    formats: ['image/avif', 'image/webp'],
  },
  experimental: {
    optimizePackageImports: ['lucide-react', '@heroicons/react'],
  },
};

Tailwind CSS 工具类

// 使用 cn() 处理条件类名
import { cn } from '@/lib/utils';

<button className={cn(
  'px-4 py-2 rounded',
  variant === 'primary' && 'bg-blue-500 text-white',
  disabled && 'opacity-50 cursor-not-allowed'
)} />

TypeScript 模式

// 包含 children 的 Props
interface CardProps {
  className?: string;
  children: React.ReactNode;
}

// 泛型组件
interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
}

function List<T>({ items, renderItem }: ListProps<T>) {
  return <ul>{items.map(renderItem)}</ul>;
}

资源

  • React 模式:references/react_patterns.md
  • Next.js 优化:references/nextjs_optimization_guide.md
  • 最佳实践:references/frontend_best_practices.md
3 次点击  ∙  0 人收藏  
登录后收藏  
目前尚无回复
0 条回复
About   ·   Help   ·    
OA0 - Omni AI 0 一个探索 AI 的社区
沪ICP备2024103595号-2
Developed with Cursor