engineering-frontend-developer
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFrontend Development Guide
前端开发指南
Overview
概述
This guide covers modern frontend development with React, Vue, Angular, and Svelte, including component architecture, performance optimization, accessibility, and testing. Use it when building web applications, component libraries, or optimizing frontend performance.
本指南涵盖基于React、Vue、Angular和Svelte的现代前端开发,包括组件架构、性能优化、无障碍访问和测试。适用于Web应用构建、组件库开发或前端性能优化场景。
Framework and Layout Decision Rules
框架与布局决策规则
- When choosing a framework, match it to team expertise and project constraints; default to React for broad ecosystem needs, Vue for progressive enhancement into existing pages, Svelte for bundle-size-critical apps, and Angular when the project requires an opinionated full-framework with built-in DI and routing.
- When implementing a design, use CSS Grid for two-dimensional page layouts and Flexbox for one-dimensional component alignment; avoid absolute positioning for layout purposes because it breaks responsive reflow.
- When building a component library, expose each component as a named export with TypeScript props interface, a Storybook story, and a unit test -- components without all three are not merged.
- When integrating with backend APIs, centralize fetch logic in a typed API client layer (e.g., a single module using
api.tsorfetchwith interceptors) so auth headers, error transforms, and retries are handled in one place.axios
- 选择框架时,需匹配团队技术能力与项目约束;若需广泛生态支持,默认选择React;若需渐进式增强现有页面,选择Vue;若对包体积要求极高,选择Svelte;若项目需要内置依赖注入(DI)和路由的全栈式框架,选择Angular。
- 实现设计时,使用CSS Grid构建二维页面布局,使用Flexbox实现一维组件对齐;避免使用绝对定位进行布局,因其会破坏响应式重排。
- 构建组件库时,需将每个组件作为命名导出,提供TypeScript props接口、Storybook示例和单元测试——缺少任意一项的组件不得合并。
- 集成后端API时,将请求逻辑集中在类型化API客户端层(例如,使用或带拦截器的
fetch实现的单个axios模块),以便在统一位置处理认证头、错误转换和重试逻辑。api.ts
Performance Decision Rules
性能决策规则
- When a page's Largest Contentful Paint exceeds 2.5 seconds in Lighthouse CI, treat it as a blocking bug -- profile with Chrome DevTools Performance tab and fix the largest bottleneck before merging.
- When adding animations, use CSS and
transformproperties (compositor-only) rather thanopacity,width, orheight/topto avoid triggering layout recalculations that cause jank.left - When the app needs offline support, register a service worker with a cache-first strategy for static assets and a network-first strategy for API requests, falling back to cached responses when offline.
- When initial JS bundle exceeds the budget (e.g., 200 KB gzipped), add route-based code splitting with or dynamic
React.lazy()and defer non-critical scripts below the fold.import() - When supporting older browsers, define a browserslist config and let the build tool (Vite, Webpack) auto-polyfill; do not manually add polyfills or feature checks unless browserslist coverage is insufficient.
- When adding images, use with WebP/AVIF sources and explicit
<picture>/widthattributes to prevent layout shift; for images below the fold, addheight.loading="lazy" - When a route is not needed on initial page load, wrap it in (or framework equivalent) with a
React.lazy()fallback so the main bundle excludes that route's code.<Suspense> - When serving static assets, configure the CDN or server to set on content-hashed filenames and
Cache-Control: public, max-age=31536000, immutableonno-cache.index.html
- 若Lighthouse CI检测到页面的最大内容绘制(Largest Contentful Paint)超过2.5秒,需将其视为阻塞性缺陷——使用Chrome DevTools性能面板分析性能,修复最大瓶颈后再合并代码。
- 添加动画时,使用CSS 和
transform属性(仅 compositor 线程处理),而非opacity、width或height/top,避免触发导致卡顿的布局重计算。left - 若应用需要离线支持,注册Service Worker,对静态资源采用缓存优先策略,对API请求采用网络优先策略,离线时回退到缓存响应。
- 若初始JS包超出预算(例如,gzip压缩后超过200 KB),使用或动态
React.lazy()实现基于路由的代码分割,并延迟加载首屏下方的非关键脚本。import() - 若需兼容旧浏览器,定义browserslist配置,让构建工具(Vite、Webpack)自动填充polyfill;除非browserslist覆盖范围不足,否则不要手动添加polyfill或进行特性检测。
- 添加图片时,使用标签搭配WebP/AVIF格式源,并设置明确的
<picture>/width属性以防止布局偏移;对首屏下方的图片添加height属性。loading="lazy" - 若某一路由无需在初始页面加载时使用,将其包裹在(或对应框架的等价方案)中,并配合
React.lazy()fallback组件,使主包不包含该路由的代码。<Suspense> - 提供静态资源时,配置CDN或服务器,对带内容哈希的文件名设置,对
Cache-Control: public, max-age=31536000, immutable设置index.html。no-cache
Accessibility Decision Rules
无障碍访问决策规则
- When building any interactive component, add ARIA attributes, keyboard handlers (,
Enter,Spaceas appropriate), and test with axe-core before marking the task complete.Escape - When building forms, associate every with a
<input>via<label>/htmlFor, provide visible error messages linked withid, and ensure the form is fully operable with keyboard-only navigation.aria-describedby - When using color to convey meaning (e.g., error states, status badges), always include a secondary indicator (icon, text, pattern) so color-blind users can distinguish states.
- When adding a modal or dropdown, trap focus inside the element while it is open and return focus to the trigger element on close; test by tabbing through the entire flow without a mouse.
- When a pull request adds a new interactive component, the PR must include an axe-core integration test that asserts zero WCAG 2.1 AA violations before it can be merged.
- 构建任何交互式组件时,添加ARIA属性、键盘事件处理器(根据需要支持、
Enter、Space),并使用axe-core测试后再标记任务完成。Escape - 构建表单时,通过/
htmlFor将每个id与<input>关联,提供通过<label>链接的可见错误提示,并确保表单完全支持纯键盘导航操作。aria-describedby - 使用颜色传达含义时(例如错误状态、状态徽章),必须包含辅助标识(图标、文本、图案),以便色盲用户区分状态。
- 添加模态框或下拉菜单时,在元素打开时将焦点锁定在内部,关闭时将焦点返回触发元素;通过纯键盘切换整个流程进行测试。
- 若拉取请求添加新的交互式组件,PR必须包含axe-core集成测试,断言零WCAG 2.1 AA级违规,方可合并。
CSS Debugging Decision Rules
CSS调试决策规则
When a layout breaks, diagnose by symptom:
- Flex child overflows its container: Add (row) or
min-width: 0(column) to the flex child. Flex items default tomin-height: 0, which prevents shrinking below content size.min-width: auto - Grid items ignore column width: Use instead of
minmax(0, 1fr). Plain1frmeans1fr, which lets content push the column wider than intended.minmax(auto, 1fr) - does not stick: Check every ancestor for
position: sticky,overflow: hidden, oroverflow: auto. Any of these creates a new scrolling context that contains the sticky element. Also verify the element has aoverflow: scroll/topvalue set.bottom - Element centered with does not center: Verify the element has an explicit
margin: auto(block) or the parent haswidth(flex child).display: flexdoes nothing on full-width block elements.margin: auto - does not work: The element needs
z-indexto create a stacking context. Also check if an ancestor creates a stacking context (viaposition: relative/absolute/fixed/sticky,transform,opacity < 1, orfilter) that limits the z-index scope.will-change - Gap between inline-block/inline elements: Whitespace in HTML creates gaps. Fix: use on the parent (preferred), or set
display: flexon parent and reset on children.font-size: 0 - 1px gap between adjacent elements: Sub-pixel rendering. Fix: use instead of
outlinefor debugging, or setborderon the parent to mask the gap.background - Text truncation with ellipsis not working: Requires all three: ,
overflow: hidden,white-space: nowrap. For multi-line truncation, usetext-overflow: ellipsiswith-webkit-line-clampanddisplay: -webkit-box.-webkit-box-orient: vertical - Container queries not applying: Verify the ancestor has (or
container-type: inline-size). The element itself cannot be its own container — the query must reference a parent.size
布局出现问题时,根据症状诊断:
- Flex子元素溢出容器:为Flex子元素添加(横向布局)或
min-width: 0(纵向布局)。Flex项默认min-height: 0,会阻止其缩小到内容尺寸以下。min-width: auto - Grid项忽略列宽:使用替代
minmax(0, 1fr)。单纯的1fr等价于1fr,会导致内容将列宽推至预期之外。minmax(auto, 1fr) - 不生效:检查所有祖先元素是否设置了
position: sticky、overflow: hidden或overflow: auto。这些属性会创建新的滚动上下文,限制sticky元素的作用范围。同时验证元素是否设置了overflow: scroll/top值。bottom - 使用居中元素无效:验证元素是否设置了明确的
margin: auto(块级元素),或父元素是否设置了width(Flex子元素)。display: flex对全宽块级元素无效。margin: auto - 不生效:元素需要设置
z-index以创建堆叠上下文。同时检查是否有祖先元素通过position: relative/absolute/fixed/sticky、transform、opacity < 1或filter创建了堆叠上下文,限制了z-index的作用范围。will-change - inline-block/inline元素间存在间隙:HTML中的空白字符会产生间隙。修复方案:为父元素设置(推荐),或为父元素设置
display: flex并在子元素上重置字体大小。font-size: 0 - 相邻元素间存在1px间隙:亚像素渲染导致。修复方案:调试时使用替代
outline,或为父元素设置border以掩盖间隙。background - 文本省略号截断不生效:需同时设置三个属性:、
overflow: hidden、white-space: nowrap。多行截断需使用text-overflow: ellipsis,配合-webkit-line-clamp和display: -webkit-box。-webkit-box-orient: vertical - 容器查询不生效:验证祖先元素是否设置了(或
container-type: inline-size)。元素自身不能作为容器——查询必须引用父元素。size
Build Tooling Decision Rules
构建工具决策规则
- Vite (default): Use for all new projects. Instant dev server via native ESM, fast HMR, Rollup-based production builds. If the project uses CommonJS-only dependencies that fail with Vite, add for those packages — do not switch to Webpack.
optimizeDeps.include - Webpack: Use only for existing projects that already use it, or when a specific Webpack-only plugin has no Vite equivalent (rare). Migrate to Vite when the opportunity arises (see Migration Decision Rules).
- Turbopack: Use only inside Next.js 14+ (). Not yet usable standalone. Provides faster dev builds than Webpack for Next.js projects. If builds are already fast (<5s), do not bother switching.
next dev --turbo - esbuild: Use for library bundling, scripts, or CLI tools — not for full applications. No HTML entry point handling, no code splitting by route. Use (esbuild wrapper) for publishing npm packages.
tsup - SWC vs Babel: Use SWC (via Vite plugin or Next.js default). SWC is 20-70x faster for transforms. Use Babel only if a project depends on a Babel-only plugin with no SWC equivalent (increasingly rare).
- Monorepo tooling: <5 packages = npm/pnpm workspaces, no extra tool. 5-20 packages = Turborepo for task caching. >20 packages or polyglot = Nx. Never add monorepo tooling to a single-package project.
- Vite(默认):用于所有新项目。通过原生ESM实现即时开发服务器、快速热模块替换(HMR)、基于Rollup的生产构建。若项目使用仅支持CommonJS的依赖导致Vite运行失败,为这些包添加配置——不要切换到Webpack。
optimizeDeps.include - Webpack:仅用于已使用Webpack的现有项目,或当特定Webpack专属插件无Vite等效方案时使用(罕见)。有机会时迁移到Vite(参见迁移决策规则)。
- Turbopack:仅在Next.js 14+中使用()。目前无法独立使用。为Next.js项目提供比Webpack更快的开发构建速度。若构建速度已足够快(<5秒),无需切换。
next dev --turbo - esbuild:用于库打包、脚本或CLI工具——不用于完整应用。不支持HTML入口点处理,不支持基于路由的代码分割。使用(esbuild封装工具)发布npm包。
tsup - SWC vs Babel:使用SWC(通过Vite插件或Next.js默认配置)。SWC的转换速度比Babel快20-70倍。仅当项目依赖无SWC等效方案的Babel专属插件时使用Babel(越来越罕见)。
- 单仓库(Monorepo)工具:<5个包 = 使用npm/pnpm工作区,无需额外工具。5-20个包 = 使用Turborepo进行任务缓存。>20个包或多语言项目 = 使用Nx。切勿为单包项目添加单仓库工具。
SSR and Server Components Decision Rules
SSR与服务器组件决策规则
When to Use SSR vs CSR vs SSG
何时使用SSR、CSR与SSG
- SSG (Static Site Generation): Use for content that changes less than once per hour (marketing pages, docs, blog posts). Build at deploy time. Fastest possible TTFB.
- SSR (Server-Side Rendering): Use for personalized content (dashboards, user profiles), SEO-critical pages with dynamic data, or pages where stale data is unacceptable. Adds server latency to every request — cache aggressively with or CDN.
Cache-Control - CSR (Client-Side Rendering): Use for authenticated-only pages (admin panels, internal tools) where SEO does not matter and interactivity is the priority. Simplest to build and deploy (static hosting).
- ISR (Incremental Static Regeneration): Use for pages that are mostly static but need periodic updates (product listings, pricing pages). Set interval based on how stale the data can be: 60s for prices, 3600s for blog posts.
revalidate
- SSG(静态站点生成):用于每小时变更少于一次的内容(营销页面、文档、博客文章)。部署时构建。拥有最快的首字节时间(TTFB)。
- SSR(服务器端渲染):用于个性化内容(仪表盘、用户资料)、SEO关键的动态数据页面,或无法接受 stale 数据的页面。每次请求都会增加服务器延迟——需通过或CDN进行激进缓存。
Cache-Control - CSR(客户端渲染):用于仅需认证访问的页面(管理面板、内部工具),此类页面无需考虑SEO,且交互性为优先需求。构建和部署最简单(静态托管)。
- ISR(增量静态再生):用于大部分为静态但需定期更新的页面(产品列表、定价页面)。根据数据可接受的 stale 程度设置间隔:价格页面设为60秒,博客文章设为3600秒。
revalidate
React Server Components (RSC) Decision Rules
React Server Components(RSC)决策规则
- Default to Server Components: Every component is a Server Component unless it needs interactivity. If a component has ,
onClick,useState, or browser APIs — it must be a Client Component (useEffect).'use client' - Data fetching: Fetch data in Server Components with directly — no
async/await, no TanStack Query, no loading states needed. The data is resolved before the HTML is sent.useEffect - Auth in Server Components: Read the session/cookie in a Server Component and pass the user object as a prop to Client Components. Never read cookies or sessions in Client Components — they execute on the client.
- When to use Server Actions vs API routes: Use Server Actions () for form submissions and mutations that are called from the UI. Use API routes (
'use server') for webhooks, third-party integrations, or endpoints called by external services./api/* - Sharing state between Server and Client Components: Pass serializable data as props from Server → Client. If you need client-side state derived from server data, initialize with the server prop and manage updates on the client.
useState - Large data sets: Stream with boundaries. Wrap the slow Server Component in
<Suspense>. The shell renders immediately; the slow component streams in when ready. Place Suspense boundaries at meaningful UI sections (sidebar, main content, comments) — not around every component.<Suspense fallback={<Skeleton />}>
- 默认使用服务器组件:除非组件需要交互性,否则所有组件均为服务器组件。若组件包含、
onClick、useState或浏览器API——必须标记为客户端组件(useEffect)。'use client' - 数据获取:在服务器组件中直接使用获取数据——无需
async/await、TanStack Query或加载状态。数据会在HTML发送前解析完成。useEffect - 服务器组件中的认证:在服务器组件中读取会话/ cookie,并将用户对象作为props传递给客户端组件。切勿在客户端组件中读取cookie或会话——客户端组件在客户端执行。
- 何时使用Server Actions vs API路由:使用Server Actions()处理表单提交和从UI调用的变更操作。使用API路由(
'use server')处理Webhook、第三方集成或外部服务调用的端点。/api/* - 服务器与客户端组件间的状态共享:将可序列化数据作为props从服务器组件传递到客户端组件。若需要基于服务器数据的客户端状态,使用服务器props初始化并在客户端管理更新。
useState - 大数据集:通过边界进行流式传输。将加载缓慢的服务器组件包裹在
<Suspense>中。页面框架会立即渲染,缓慢加载的组件准备就绪后流式传入。将Suspense边界放置在有意义的UI区域(侧边栏、主内容、评论区)——不要包裹每个组件。<Suspense fallback={<Skeleton />}>
Hydration Error Decision Tree
水合错误决策树
- Error: "Text content does not match": A value differs between server and client render. Common causes:
- ,
Date.now(), orMath.random()in render → move tonew Date().toLocaleString()+useEffect.useState - conditional rendering → use
typeof window !== 'undefined'to set auseEffectflag.hasMounted - Browser extensions injecting DOM nodes → not your bug, but test in incognito to confirm.
- Error: "Hydration failed because the server rendered HTML didn't match": A structural difference (different elements). Common causes:
- nested inside
<p>, or<p>inside<div>→ fix the nesting, HTML spec does not allow it.<p> - A third-party component renders differently on server vs client → wrap in .
dynamic(() => import(...), { ssr: false }) - Missing closing tags or self-closing tags where HTML requires explicit close.
- 错误:"文本内容不匹配":服务器与客户端渲染的值不一致。常见原因:
- 渲染中使用、
Date.now()或Math.random()→ 移至new Date().toLocaleString()+useEffect中。useState - 使用进行条件渲染 → 使用
typeof window !== 'undefined'设置useEffect标志。hasMounted - 浏览器扩展注入DOM节点 → 非代码问题,可在隐身模式下测试确认。
- 渲染中使用
- 错误:"水合失败,因为服务器渲染的HTML不匹配":结构差异(元素不同)。常见原因:
- 嵌套在
<p>内,或<p>嵌套在<div>内 → 修复嵌套结构,HTML规范不允许此类嵌套。<p> - 第三方组件在服务器与客户端渲染结果不同 → 使用包裹。
dynamic(() => import(...), { ssr: false }) - 缺少闭合标签或在HTML要求显式闭合的位置使用自闭合标签。
Performance Debugging Workflow
性能调试流程
When a page is slow, follow this sequence — do not skip steps:
页面加载缓慢时,遵循以下步骤——不要跳过:
Step 1: Identify the bottleneck type
步骤1:识别瓶颈类型
- Run Lighthouse. Check which metric is failing:
- LCP >2.5s: The largest visible element loads too slowly. Go to Step 2.
- FID/INP >200ms: User interaction is blocked by JavaScript. Go to Step 3.
- CLS >0.1: Layout shifts after initial paint. Go to Step 4.
- 运行Lighthouse。检查哪个指标不达标:
- LCP >2.5秒:最大可见元素加载过慢。进入步骤2。
- FID/INP >200毫秒:用户交互被JavaScript阻塞。进入步骤3。
- CLS >0.1:初始绘制后发生布局偏移。进入步骤4。
Step 2: Fix LCP
步骤2:修复LCP
- Check what the LCP element is (Lighthouse shows it). Usually: hero image, heading text, or video.
- If image: Add (Next.js) or
priority. Add explicitfetchpriority="high"/width. Serve in WebP/AVIF. If served from a CDN, verify cache headers.height - If text: Check for render-blocking fonts. Use or
font-display: swap. Preload the critical font file withfont-display: optional.<link rel="preload" as="font" crossorigin> - If blocked by JS: The bundle is too large. Check Step 3. The LCP element cannot render until the JS that creates it is loaded and executed.
- Check the server response time (TTFB). If TTFB >600ms, the bottleneck is backend or CDN — not frontend.
- 确定LCP元素(Lighthouse会显示)。通常为:首屏图片、标题文本或视频。
- 若为图片:添加(Next.js)或
priority。设置明确的fetchpriority="high"/width。使用WebP/AVIF格式。若通过CDN提供,验证缓存头。height - 若为文本:检查是否存在阻塞渲染的字体。使用或
font-display: swap。通过font-display: optional预加载关键字体文件。<link rel="preload" as="font" crossorigin> - 若为JS阻塞:包体积过大。参见步骤3。LCP元素需等待创建它的JS加载并执行后才能渲染。
- 检查服务器响应时间(TTFB)。若TTFB >600毫秒,瓶颈在后端或CDN——而非前端。
Step 3: Fix INP (Interaction to Next Paint)
步骤3:修复INP(交互到下一次绘制的时间)
- Open Chrome DevTools → Performance → record a click/type interaction.
- Find the Long Task (>50ms yellow bar). Click it to see the call stack.
- If the long task is your code: Break the work into smaller chunks with ,
requestIdleCallback(Chrome 115+), orscheduler.yield()to yield to the browser between frames.setTimeout(fn, 0) - If the long task is React re-rendering: Open React DevTools Profiler. Find the component that re-renders. Common fixes: (expensive children),
React.memo(derived values), or move state closer to where it is used. If >500 components re-render on a single state change, the state is too high in the tree.useMemo - If the long task is third-party script (analytics, ads): Defer with or
asyncattribute, or load afterdefer.requestIdleCallback
- 打开Chrome DevTools → 性能 → 录制点击/输入交互。
- 找到长任务(>50毫秒的黄色条)。点击查看调用栈。
- 若长任务来自自有代码:使用、
requestIdleCallback(Chrome 115+)或scheduler.yield()将工作拆分为更小的块,在帧之间让渡给浏览器。setTimeout(fn, 0) - 若长任务来自React重渲染:打开React DevTools Profiler。找到重渲染的组件。常见修复方案:(优化开销大的子组件)、
React.memo(缓存派生值),或将状态移至更靠近使用位置的地方。若单次状态变更导致>500个组件重渲染,说明状态在组件树中的层级过高。useMemo - 若长任务来自第三方脚本(分析、广告):使用或
async属性延迟加载,或在defer后加载。requestIdleCallback
Step 4: Fix CLS
步骤4:修复CLS
- Check which element shifts (Lighthouse shows it, or use DevTools → "Layout Shift Regions").
- Image/video without dimensions: Add and
widthattributes (orheightCSS). The browser reserves space before the asset loads.aspect-ratio - Font swap: The fallback font has different metrics than the web font. Use in
size-adjustto match metrics, or use@font-faceto eliminate the swap entirely.font-display: optional - Dynamic content injected above the fold: Ads, banners, cookie notices. Reserve space with on the container. If the content height varies, use
min-heightto prevent shifts from propagating.contain: layout - Late-loading CSS: If a stylesheet loads after first paint and changes visible layout, inline the critical CSS or preload the stylesheet.
- 确定哪个元素发生偏移(Lighthouse会显示,或使用DevTools → "布局偏移区域")。
- 图片/视频未设置尺寸:添加和
width属性(或CSSheight)。浏览器会在资源加载前预留空间。aspect-ratio - 字体替换: fallback字体与Web字体的度量不同。在中使用
@font-face匹配度量,或使用size-adjust完全消除替换。font-display: optional - 首屏上方注入动态内容:广告、横幅、Cookie通知。为容器设置预留空间。若内容高度可变,使用
min-height防止偏移扩散。contain: layout - CSS加载过晚:若样式表在首次绘制后加载并改变可见布局,内联关键CSS或预加载样式表。
Code Quality Decision Rules
代码质量决策规则
- When writing tests, require every component to have at least one unit test covering its primary render path and one interaction test (click, keyboard) -- enforce via a CI coverage gate of 80% line coverage minimum.
- When starting a project, enable in
strict: trueon day one; retrofitting strict mode later is exponentially harder as the codebase grows.tsconfig.json - When an API call or async operation fails, display a user-facing error message with a retry action -- never swallow errors silently or show raw exception text.
- When a component file exceeds 300 lines, split it into smaller sub-components with a shared barrel export; large files signal mixed responsibilities.
- When setting up CI, include lint (ESLint), type-check (), test (Vitest/Jest), and bundle-size check as required gates -- all four must pass before merge.
tsc --noEmit
- 编写测试时,要求每个组件至少有一个覆盖主要渲染路径的单元测试和一个交互测试(点击、键盘操作)——通过CI覆盖率门限强制要求最低80%的行覆盖率。
- 启动项目时,第一天就在中启用
tsconfig.json;随着代码库增长,后期再适配严格模式会指数级困难。strict: true - API调用或异步操作失败时,显示面向用户的错误提示及重试操作——切勿静默吞掉错误或显示原始异常文本。
- 组件文件超过300行时,拆分为更小的子组件,并使用共享桶导出;大文件意味着职责混合。
- 设置CI时,必须包含代码检查(ESLint)、类型检查()、测试(Vitest/Jest)和包体积检查作为必填门限——四项全部通过后方可合并。
tsc --noEmit
Workflow
工作流程
Step 1: Project Setup and Architecture
步骤1:项目搭建与架构
- Set up modern development environment with proper tooling.
- Configure build optimization and performance monitoring.
- Establish testing framework and CI/CD integration.
- Create component architecture and design system foundation.
- 使用合适的工具搭建现代开发环境。
- 配置构建优化与性能监控。
- 建立测试框架与CI/CD集成。
- 创建组件架构与设计系统基础。
Step 2: Component Development
步骤2:组件开发
- Create reusable component library with proper TypeScript types.
- Implement responsive design with mobile-first approach.
- Build accessibility into components from the start.
- Create comprehensive unit tests for all components.
- 创建带TypeScript类型的可复用组件库。
- 采用移动端优先的实现响应式设计。
- 从组件开发初期就融入无障碍访问支持。
- 为所有组件编写全面的单元测试。
Step 3: Performance Optimization
步骤3:性能优化
- Implement code splitting and lazy loading strategies.
- Optimize images and assets for web delivery.
- Monitor Core Web Vitals and optimize accordingly.
- Set up performance budgets and monitoring.
- 实现代码分割与懒加载策略。
- 优化图片与资源以适配Web交付。
- 监控Core Web Vitals并进行相应优化。
- 设置性能预算与监控机制。
Step 4: Testing and Quality Assurance
步骤4:测试与质量保证
- Write comprehensive unit and integration tests.
- Perform accessibility testing with real assistive technologies.
- Test cross-browser compatibility and responsive behavior.
- Implement end-to-end testing for critical user flows.
- 编写全面的单元测试与集成测试。
- 使用真实辅助技术进行无障碍访问测试。
- 测试跨浏览器兼容性与响应式表现。
- 为关键用户流程实现端到端测试。
Reference
参考
Lighthouse CI Targets
Lighthouse CI目标
- Performance score: 90+
- All interactive elements keyboard-navigable with visible focus indicators
- axe-core: zero violations at WCAG 2.1 AA level
- Bundle size: < 200 KB gzipped for initial JS (enforce with or equivalent)
bundlesize - Zero TypeScript casts in production code;
anyenabled in tsconfigstrict: true
- 性能得分:90+
- 所有交互式元素可通过键盘导航,且焦点指示器可见
- axe-core:零WCAG 2.1 AA级违规
- 包体积:初始JS包gzip压缩后< 200 KB(使用或等效工具强制要求)
bundlesize - 生产代码中零TypeScript 类型转换;
any中启用tsconfigstrict: true
Migration Decision Rules
迁移决策规则
- CRA to Vite: Migrate when CRA's build time exceeds 30s or eject pressure mounts. Steps: replace with
react-scripts+vite, move@vitejs/plugin-reactto root, updateindex.html→process.env, fix any CommonJS imports. Budget: 2-4 hours for small apps, 1-2 days for large apps with custom Webpack config.import.meta.env - Pages Router to App Router (Next.js): Migrate incrementally. Move one route at a time to directory. Start with static/simple pages, leave complex pages (with getServerSideProps + complex state) for last. Do not migrate the entire app at once. Budget: 1 route per day for complex apps.
app/ - JavaScript to TypeScript: Enable in tsconfig and rename files one at a time from
allowJs: true→.js. Start with leaf components (no dependencies), work inward. Enforce.tsxon new files from day one; create astrict: truethat extends base if needed. Budget: ~10 files per day.tsconfig.strict.json - CSS Modules to Tailwind: Do not rewrite all styles at once. Install Tailwind alongside CSS Modules. New components use Tailwind; migrate old components only when you touch them for other reasons. Budget: per-component during normal development.
- Class components to hooks: Migrate only when you need to modify the component for a feature change. Do not migrate stable, untouched class components — they work fine. When migrating: →
componentDidMount,useEffect(..., [])→componentDidUpdatewith deps,useEffect→this.state.useState
- CRA迁移到Vite:当CRA构建时间超过30秒或出现 eject 需求时进行迁移。步骤:用+
vite替换@vitejs/plugin-react,将react-scripts移至根目录,将index.html改为process.env,修复CommonJS导入问题。时间预算:小型应用2-4小时,带自定义Webpack配置的大型应用1-2天。import.meta.env - Pages Router迁移到App Router(Next.js):增量迁移。将路由逐个移至目录。从静态/简单页面开始,最后迁移复杂页面(带getServerSideProps + 复杂状态)。切勿一次性迁移整个应用。时间预算:复杂应用每天迁移1个路由。
app/ - JavaScript迁移到TypeScript:在tsconfig中启用,将文件从
allowJs: true逐个重命名为.js。从叶子组件(无依赖)开始,向内推进。从第一天起对新文件强制启用.tsx;若需要,创建继承基础配置的strict: true。时间预算:每天约10个文件。tsconfig.strict.json - CSS Modules迁移到Tailwind:不要一次性重写所有样式。在CSS Modules旁安装Tailwind。新组件使用Tailwind;仅在因其他需求修改旧组件时进行迁移。时间预算:在日常开发中逐个组件迁移。
- 类组件迁移到Hooks:仅在需要为功能变更修改组件时进行迁移。无需迁移稳定、未改动的类组件——它们运行正常。迁移时:→
componentDidMount,useEffect(..., [])→ 带依赖的componentDidUpdate,useEffect→this.state。useState
State Management Decision Matrix
状态管理决策矩阵
- <5 components sharing state: Lift state up with props. No library needed. If prop drilling goes >3 levels, add React Context for that specific slice.
- 5-15 components with shared state: Use React Context + for structured state, or Zustand for simpler API. If the state is server data, use TanStack Query instead — not Context.
useReducer - >15 components or complex derived state: Zustand (simple, small bundle) or Jotai (atomic, bottom-up). Use Redux Toolkit only if the team already knows Redux. Never introduce Redux to a new project.
- Server state (API data, caching, sync): TanStack Query (React), SWR (simpler needs), or Apollo Client (GraphQL). Never store server data in a client state manager (Zustand, Redux) — it causes stale data and duplicate cache management.
- Form state: react-hook-form for complex forms (>5 fields, validation, dynamic fields). Native for simple forms (<5 fields, no complex validation). Never use a global state manager for form state.
useState - URL state (filters, pagination, search): Use URL search params () as the source of truth. Sync to component state only for derived values. This makes the state shareable, bookmarkable, and back-button friendly.
useSearchParams
- <5个组件共享状态:通过props提升状态。无需使用库。若props传递层级超过3层,为该特定状态切片添加React Context。
- 5-15个组件共享状态:使用React Context + 实现结构化状态,或使用Zustand简化API。若状态为服务器数据,使用TanStack Query而非Context。
useReducer - >15个组件或复杂派生状态:使用Zustand(简洁、小包体积)或Jotai(原子化、自底向上)。仅当团队已掌握Redux时使用Redux Toolkit。切勿在新项目中引入Redux。
- 服务器状态(API数据、缓存、同步):使用TanStack Query(React)、SWR(需求较简单时)或Apollo Client(GraphQL)。切勿将服务器数据存储在客户端状态管理器(Zustand、Redux)中——会导致数据 stale 和重复缓存管理。
- 表单状态:复杂表单(>5个字段、验证、动态字段)使用react-hook-form。简单表单(<5个字段、无复杂验证)使用原生。切勿使用全局状态管理器管理表单状态。
useState - URL状态(筛选、分页、搜索):使用URL搜索参数()作为单一数据源。仅为派生值同步到组件状态。这样状态可共享、可收藏、支持后退按钮。
useSearchParams
Self-Verification Protocol
自我验证协议
After completing a frontend implementation, verify:
- Run Lighthouse CI and confirm: Performance >=90, Accessibility >=90, Best Practices >=90. If any score drops below 90, fix before merge.
- Run or
npx axe-coreon every new page/component. Zero WCAG 2.1 AA violations.axe-playwright - Test keyboard navigation: Tab through the entire page. Every interactive element must be reachable and operable. Focus indicators must be visible.
- Open the browser DevTools Performance tab, record a user interaction, and check for: layout thrashing (forced reflows), long tasks >50ms, excessive re-renders.
- Check bundle size: run or check the build output. If initial JS exceeds 200KB gzipped, investigate what is in the bundle (use
npx bundlesize).npx source-map-explorer - Test responsive layout at 320px, 768px, and 1280px. No horizontal scroll, no overlapping elements, no unreadable text.
- Test with browser devtools network throttling set to "Slow 3G." If the page is unusable, add loading states and optimize critical rendering path.
完成前端实现后,验证以下内容:
- 运行Lighthouse CI,确认:性能>=90,无障碍访问>=90,最佳实践>=90。若任意得分低于90,修复后再合并。
- 在每个新页面/组件上运行或
npx axe-core。零WCAG 2.1 AA级违规。axe-playwright - 测试键盘导航:遍历整个页面。所有交互式元素必须可访问且可操作。焦点指示器必须可见。
- 打开浏览器DevTools性能面板,录制用户交互,检查:布局抖动(强制重排)、>50毫秒的长任务、过度重渲染。
- 检查包体积:运行或查看构建输出。若初始JS包gzip压缩后超过200KB,使用
npx bundlesize分析包内容。npx source-map-explorer - 在320px、768px和1280px视口下测试响应式布局。无横向滚动、无重叠元素、无不清晰文本。
- 在浏览器DevTools中将网络节流设置为"Slow 3G"测试。若页面无法使用,添加加载状态并优化关键渲染路径。
Failure Recovery
故障恢复
- Component re-renders excessively: Use React DevTools Profiler to identify the cause. Common fixes: memoize with (for expensive children),
React.memo/useMemo(for derived values/callbacks passed as props), or move state closer to where it is used.useCallback - Bundle size suddenly increased: Run to find the culprit. Common causes: importing an entire library (
source-map-explorer→import _ from 'lodash'), accidentally bundling a dev dependency, or a heavy polyfill.import groupBy from 'lodash/groupBy' - Hydration mismatch (SSR/SSG): The server-rendered HTML differs from client render. Common causes: using or
Date.now()in render, accessingMath.random()/windowduring SSR, or conditional rendering based on client-only state. Fix: usedocumentfor client-only values, oruseEffectas last resort.suppressHydrationWarning - CSS layout breaks at specific viewport: Check for: hardcoded pixel widths, missing on flex children,
min-width: 0clipping content, oroverflow: hiddenelements escaping their container. Use CSS Grid withposition: absoluteinstead of fixed widths.minmax() - API calls fire too many times: Check for missing or incorrect dependency arrays. If using TanStack Query, set
useEffectto avoid refetching on every mount. If usingstaleTimefor data fetching, consider switching to a data fetching library entirely.useEffect
- 组件过度重渲染:使用React DevTools Profiler确定原因。常见修复方案:使用memoize开销大的子组件,使用
React.memo/useMemo缓存派生值/传递给props的回调,或将状态移至更靠近使用位置的地方。useCallback - 包体积突然增大:运行找到问题根源。常见原因:导入整个库(
source-map-explorer→import _ from 'lodash')、意外打包开发依赖、或引入重型polyfill。import groupBy from 'lodash/groupBy' - 水合不匹配(SSR/SSG):服务器渲染的HTML与客户端渲染结果不同。常见原因:渲染中使用或
Date.now()、SSR期间访问Math.random()/window、或基于客户端独有状态进行条件渲染。修复方案:使用document处理客户端独有值,或作为最后手段使用useEffect。suppressHydrationWarning - CSS布局在特定视口下失效:检查:硬编码像素宽度、Flex子元素缺少、
min-width: 0裁剪内容、或overflow: hidden元素超出容器。使用带position: absolute的CSS Grid替代固定宽度。minmax() - API调用触发过于频繁:检查依赖数组是否缺失或错误。若使用TanStack Query,设置
useEffect避免每次挂载都重新请求。若使用staleTime获取数据,考虑完全切换到数据获取库。useEffect
Existing Codebase Orientation
现有代码库上手指南
When joining an existing frontend project:
- Run /
npm start(5 min) — If it fails, fix the dev environment first.npm run dev - Check the tech stack (5 min) — Framework (React/Vue/Angular/Svelte), bundler (Vite/Webpack/Turbopack), CSS approach (Tailwind/CSS Modules/styled-components), state management, testing library.
- Run the test suite (5 min) — . Note coverage, test types, and which flows are untested.
npm test - Open the browser DevTools (10 min) — Check bundle size (Network tab), console errors, Lighthouse score. These are your baseline numbers.
- Read the component tree (10 min) — Start from the app root. Map the top-level routes and their key components. Identify shared components (design system, layout).
- Check for tech debt signals (5 min) — Any casts?
anycomments? Files >500 lines? Inline styles? These indicate areas of fragility.eslint-disable - Identify the data flow (10 min) — How does data get from the API to the UI? Is there a centralized API client? Are there loading/error states? Is server state managed with a library or manually?
加入现有前端项目时:
- 运行/
npm start(5分钟)——若运行失败,先修复开发环境。npm run dev - 检查技术栈(5分钟)——框架(React/Vue/Angular/Svelte)、打包工具(Vite/Webpack/Turbopack)、CSS方案(Tailwind/CSS Modules/styled-components)、状态管理、测试库。
- 运行测试套件(5分钟)——。记录覆盖率、测试类型及未覆盖的流程。
npm test - 打开浏览器DevTools(10分钟)——检查包体积(网络面板)、控制台错误、Lighthouse得分。这些是你的基准数据。
- 阅读组件树(10分钟)——从应用根组件开始。梳理顶层路由及其关键组件。识别共享组件(设计系统、布局)。
- 检查技术债务信号(5分钟)——是否存在类型转换?
any注释?文件超过500行?内联样式?这些都表明存在脆弱区域。eslint-disable - 梳理数据流(10分钟)——数据如何从API传递到UI?是否有集中式API客户端?是否有加载/错误状态?服务器状态是通过库管理还是手动管理?
Scripts
脚本
- -- Analyze a build output directory for JS and CSS bundle sizes, with gzip estimates and configurable warning/error thresholds. Run with
scripts/check_bundle.shfor options.--help
See DataTable Component for a full virtualized DataTable implementation in React + TypeScript.
See React Component Patterns for compound components, custom hooks, error boundaries, optimistic UI, and form validation patterns.
See TypeScript Patterns for discriminated unions, polymorphic components, branded types, and type-safe API clients.
See CSS Patterns for modern CSS Grid layouts, container queries, theming, view transitions, and :has() selectors.
- -- 分析构建输出目录的JS和CSS包体积,提供gzip压缩估计值及可配置的警告/错误阈值。运行
scripts/check_bundle.sh查看选项。--help
查看DataTable组件获取基于React + TypeScript的完整虚拟化DataTable实现。
查看React组件模式了解复合组件、自定义Hooks、错误边界、乐观UI和表单验证模式。
查看TypeScript模式了解判别式联合、多态组件、品牌类型和类型安全API客户端。
查看CSS模式了解现代CSS Grid布局、容器查询、主题、视图过渡和:has()选择器。