senior-frontend senior-frontend

高级前端技能,专注于React、Next.js、TypeScript和Tailwind CSS应用的前端开发模式、性能优化和自动化工具。

前端开发 0 次安装 0 次浏览 更新于 3/5/2026

高级前端

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

目录


项目搭建

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

工作流程:创建新前端项目

  1. 使用项目名称和模板运行搭建工具:

    python scripts/frontend_scaffolder.py 我的应用 --template nextjs
    
  2. 添加可选功能(认证、API、表单、测试、storybook):

    python scripts/frontend_scaffolder.py 仪表盘 --template nextjs --features auth,api
    
  3. 导航到项目并安装依赖:

    cd 我的应用 && npm install
    
  4. 启动开发服务器:

    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 + 测试库
--dry-run 预览文件而不创建它们

生成结构(Next.js)

我的应用/
├── app/
│   ├── layout.tsx        # 根布局带字体
│   ├── page.tsx          # 首页
│   ├── globals.css       # Tailwind + CSS变量
│   └── api/health/route.ts
├── components/
│   ├── ui/               # 按钮,输入框,卡片
│   └── layout/           # 头部,底部,侧边栏
├── hooks/                # useDebounce, useLocalStorage
├── lib/                  # 工具(cn), 常量
├── types/                # TypeScript接口
├── tailwind.config.ts
├── next.config.js
└── package.json

组件生成

生成带TypeScript、测试和Storybook故事的React组件。

工作流程:创建新组件

  1. 生成一个客户端组件:

    python scripts/component_generator.py 按钮 --dir src/components/ui
    
  2. 生成一个服务器组件:

    python scripts/component_generator.py 商品卡片 --type server
    
  3. 生成带测试和故事文件:

    python scripts/component_generator.py 用户档案 --with-test --with-story
    
  4. 生成一个自定义钩子:

    python scripts/component_generator.py 表单验证 --type hook
    

生成器选项

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

生成组件示例

'use client';

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

interface 按钮Props {
  className?: string;
  children?: React.ReactNode;
}

export function 按钮({ className, children }: 按钮Props) {
  return (
    <div className={cn('', className)}>
      {children}
    </div>
  );
}

包分析

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

工作流程:优化包大小

  1. 在项目上运行分析器:

    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. 以详细模式重新运行,检查导入模式:

    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>内容1</Tabs.Panel>
  <Tabs.Panel>内容2</Tabs.Panel>
</Tabs>

自定义钩子

提取可重用的逻辑:

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);

渲染属性

共享渲染逻辑:

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

服务器与客户端组件

默认使用服务器组件。当你需要时添加’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
/>

// 响应式图像填充
<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(<按钮 onClick={onClick}>点击我</按钮>);

  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',
  变体 === 'primary' && 'bg-blue-500 text-white',
  禁用 && '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