資深前端工程師
React / Next.js 應用的前端開發模式、效能優化與自動化工具。
目錄
專案搭建
建立一個新的 Next.js 或 React 專案,內含 TypeScript、Tailwind CSS 以及最佳實踐配置。
工作流程:建立新前端專案
-
使用專案名稱和模板執行搭建腳本:
python scripts/frontend_scaffolder.py my-app --template nextjs -
加入可選功能(auth, api, forms, testing, storybook):
python scripts/frontend_scaffolder.py dashboard --template nextjs --features auth,api -
進入專案目錄並安裝依賴:
cd my-app && npm install -
啟動開發伺服器:
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
├── lib/ # utils (cn)、constants
├── types/ # TypeScript 介面
├── tailwind.config.ts
├── next.config.js
└── package.json
元件生成
生成包含 TypeScript、測試和 Storybook 故事的 React 元件。
工作流程:建立新元件
-
生成一個客戶端元件:
python scripts/component_generator.py Button --dir src/components/ui -
生成一個伺服器元件:
python scripts/component_generator.py ProductCard --type server -
生成時包含測試和故事檔案:
python scripts/component_generator.py UserProfile --with-test --with-story -
生成一個自訂 Hook:
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 和專案結構,尋找套件最佳化的機會。
工作流程:最佳化套件大小
-
對你的專案執行分析器:
python scripts/bundle_analyzer.py /path/to/project -
檢視健康分數和問題:
Bundle Health Score: 75/100 (C) HEAVY DEPENDENCIES: moment (290KB) Alternative: date-fns (12KB) or dayjs (2KB) lodash (71KB) Alternative: lodash-es with tree-shaking -
透過取代重量級依賴項來套用建議的修正。
-
使用詳細模式重新執行,檢查導入模式:
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 | lodash-es 搭配 tree-shaking |
| 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;
// Usage
<Tabs>
<Tabs.List>
<Tabs.Tab>One</Tabs.Tab>
<Tabs.Tab>Two</Tabs.Tab>
</Tabs.List>
<Tabs.Panel>Content 1</Tabs.Panel>
<Tabs.Panel>Content 2</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;
}
// Usage
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 });
}
// Usage
<DataFetcher
url="/api/users"
render={({ data, loading }) =>
loading ? <Spinner /> : <UserList users={data} />
}
/>
Next.js 優化
參考:references/nextjs_optimization_guide.md
Server 與 Client 元件
預設使用 Server Components。僅在需要以下功能時加入 'use client':
- 事件處理 (onClick, onChange)
- 狀態 (useState, useReducer)
- 副作用 (useEffect)
- 瀏覽器 API
// Server Component (預設) - 不需要 'use client'
async function ProductPage({ params }) {
const product = await getProduct(params.id); // 伺服器端擷取
return (
<div>
<h1>{product.name}</h1>
<AddToCartButton productId={product.id} /> {/* Client 元件 */}
</div>
);
}
// Client Component
'use client';
function AddToCartButton({ productId }) {
const [adding, setAdding] = useState(false);
return <button onClick={() => addToCart(productId)}>Add</button>;
}
圖像優化
import Image from 'next/image';
// 首屏 - 立即載入
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority
/>
// 響應式圖像,使用 fill
<div className="relative aspect-video">
<Image
src="/product.jpg"
alt="Product"
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
無障礙檢查清單
- 語意化 HTML:使用正確的元素(
<button>、<nav>、<main>) - 鍵盤導航:所有互動元素應可聚焦
- ARIA 標籤:為圖示和複雜元件提供標籤
- 色彩對比:一般文字最小對比度 4.5:1
- 焦點指示器:具有可見的焦點狀態
// 無障礙按鈕
<button
type="button"
aria-label="Close dialog"
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">
Skip to main content
</a>
測試策略
// 使用 React Testing Library 進行元件測試
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
test('button triggers action on click', async () => {
const onClick = vi.fn();
render(<Button onClick={onClick}>Click me</Button>);
await userEvent.click(screen.getByRole('button'));
expect(onClick).toHaveBeenCalledTimes(1);
});
// 測試無障礙
テスト('dialog is accessible', async () => {
render(<Dialog open={true} title="Confirm" />);
expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByRole('dialog')).toHaveAttribute('aria-labelledby');
});
快速參考
常見 Next.js 配置
// next.config.js
const nextConfig = {
images: {
remotePatterns: [{ protocol: 'https', 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 - Forcing-question 資料庫 (Matt Pocock grill):
references/forcing_questions.md - 組合地圖 (應分流給哪個專家):
references/composition_map.md
假設與可驗證的成功標準(Karpathy 學科)
在此技能搭建元件、推薦框架或審計套件之前,必須先釐清以下四個假設。
- 主要使用者裝置 + 網路 — mobile-4G、desktop-fiber、low-end-Android 或 corporate-network。影響所有效能決策。
- LCP 目標(毫秒) — 一個具體數字,而非「很快」。影響套件預算和渲染選擇。
- SEO 依賴 vs. 需要驗證 — 影響渲染方式 (SSR/SSG/RSC vs. SPA)。
- WCAG 目標 + 指定的無障礙負責人 — AA、AAA 或盡力而為。影響無障礙投資和 CI 門檻。
可驗證的成功標準 (Karpathy #4) — 每個推薦都必須包含:
- 在主要裝置上第 75 百分位的 Core Web Vitals 目標 (LCP、INP、CLS)
- 每條路由的 JS 套件預算 (KB-gzip)
- Lighthouse 無障礙分數下限 + 效能分數下限
如果缺少上述任何一項,該推薦即為不完整 — 應返回 forcing-question 資料庫的第 2 回合。
scripts/frontend_decision_engine.py 工具實作了這些檢查:如果缺少四個假設輸入,它會拒絕推薦設定檔,並輸出匹配設定檔的可驗證閾值。
自訂設定檔
profiles/ 中有四個內建設定檔,可校準所有推薦:
| 設定檔 | 何時選擇 | LCP 目標 (mobile-4G p75) | 套件預算 |
|---|---|---|---|
next-app-router | SaaS 面向客戶、SEO + 動態內容、RSC 優先 | 2000ms | 150 KB-gzip / 路由 |
remix-or-sveltekit | 主要使用 mobile-4G、低 JS 優先、漸進增強 | 1500ms | 80 KB-gzip / 路由 |
vite-spa | 需要驗證的應用、主要使用桌面/公司網路 | 2500ms | 200 KB 初始 + 80 KB / 路由 |
astro-or-static | 行銷 / 文件 / 部落格、近乎零寫入、SEO 關鍵 | 1200ms | 30 KB JS / 頁面 |
透過以下指令選擇設定檔:
python scripts/frontend_decision_engine.py \
--primary-device mobile-4g --lcp-target-ms 2000 \
--seo-dependent true --auth-walled false --team-size 5
該工具會回傳最匹配的設定檔、差距在 15% 以內的次佳選擇、技術棧建議、該設定檔應避免的反模式,以及所需的 CI 門檻。
若要新增自訂設定檔(例如,用於組織內部工具),請將 profiles/vite-spa.json 複製為 profiles/<your-org>.json,並調整 constraints 和 success_thresholds。
組合地圖
此技能不會重新實作由 POWERFUL 級專家負責的範疇。它會將這些範疇分流給專家。請參閱 references/composition_map.md 以取得完整的路由表。主要分流項目:
| 關注領域 | 分流至 |
|---|---|
| WCAG 審計、對比度、螢幕閱讀器 | engineering-team/skills/a11y-audit/ |
| 套件分析 + 運行時效能 | engineering/skills/performance-profiler/ |
| 電影級 / 滾動敘事登陸頁 | engineering-team/skills/epic-design/ |
| Apple HIG (iOS / macOS / visionOS) | product-team/skills/apple-hig-expert/ |
| 預提交 Karpathy 審查 | engineering/karpathy-coder/ |
| 預先架構審查 | engineering/grill-me/ |
cs-frontend-engineer 代理透過 context: fork 協調這些分流。可從其他代理透過 Agent({subagent_type: "cs-frontend-engineer", prompt: "..."}) 呼叫它。
…
[因翻譯而截斷]