Core Web Vitals
LCP
< 2.5s
Largest Contentful Paint
FID
< 100ms
First Input Delay
CLS
< 0.1
Cumulative Layout Shift
- •
- •
- •
- •
tsx
1// Lazy load heavy components2import dynamic from 'next/dynamic';3 4// Only load when needed5const HeavyChart = dynamic(6 () => import('@/components/HeavyChart'),7 {8 loading: () => <ChartSkeleton />,9 ssr: false, // Skip SSR for client-only components10 }11);12 13// Use in component14export function Dashboard() {15 return (16 <Suspense fallback={<ChartSkeleton />}>17 <HeavyChart data={data} />18 </Suspense>19 );20}tsx
1// ❌ Bad: Animation on every item2{items.map((item, i) => {3 const motion = useMotion({ type: 'fadeIn', delay: i * 100 });4 return <div ref={motion.ref} style={motion.style}>{item}</div>;5})}6 7// ✅ Good: Animate container only8const containerMotion = useMotion({ type: 'fadeIn' });9 10<div ref={containerMotion.ref} style={containerMotion.style}>11 {items.map((item) => (12 <div key={item.id}>{item.content}</div>13 ))}14</div>15 16// ✅ Better: Limit stagger to first N items17{items.slice(0, 5).map((item, i) => {18 const motion = useMotion({ type: 'slideUp', delay: i * 50 });19 return <div ref={motion.ref} style={motion.style}>{item}</div>;20})}tsx
1// hua.config.ts2export default {3 i18n: {4 defaultLanguage: 'ko',5 // Only load namespaces you need6 namespaces: ['common', 'home'],7 8 // Preload critical namespaces9 preloadNamespaces: ['common'],10 11 // Cache translations12 cache: {13 enabled: true,14 maxAge: 1000 * 60 * 60, // 1 hour15 },16 },17};18 19// Split translations by page20// /translations/ko/home.json - only for home page21// /translations/ko/dashboard.json - only for dashboardtsx
1// next.config.js2module.exports = {3 // Enable SWC minification4 swcMinify: true,5 6 // Optimize images7 images: {8 formats: ['image/avif', 'image/webp'],9 },10 11 // Tree shake unused code12 modularizeImports: {13 '@phosphor-icons/react': {14 transform: '@phosphor-icons/react/{{member}}',15 },16 '@hua-labs/ui': {17 transform: '@hua-labs/ui/components/{{member}}',18 },19 },20};tsx
1import { memo, useMemo, useCallback } from 'react';2 3// Memoize expensive component4const ExpensiveList = memo(function ExpensiveList({ items }) {5 return (6 <ul>7 {items.map(item => <li key={item.id}>{item.name}</li>)}8 </ul>9 );10});11 12// Memoize expensive calculations13function Dashboard({ data }) {14 const processedData = useMemo(() => {15 return data.map(item => heavyCalculation(item));16 }, [data]);17 18 // Memoize callbacks passed to children19 const handleClick = useCallback((id) => {20 console.log('clicked', id);21 }, []);22 23 return <ExpensiveList items={processedData} onClick={handleClick} />;24}tsx
1// Respect user preferences2import { useReducedMotion } from '@hua-labs/motion-core';3 4function AnimatedCard({ children }) {5 const prefersReducedMotion = useReducedMotion();6 7 const motion = useMotion({8 type: prefersReducedMotion ? 'none' : 'fadeIn',9 duration: prefersReducedMotion ? 0 : 500,10 });11 12 return (13 <div ref={motion.ref} style={motion.style}>14 {children}15 </div>16 );17}18 19// Or skip animation entirely20function Card({ children }) {21 const prefersReducedMotion = useReducedMotion();22 23 if (prefersReducedMotion) {24 return <div>{children}</div>;25 }26 27 const motion = useMotion({ type: 'fadeIn' });28 return <div ref={motion.ref} style={motion.style}>{children}</div>;29}ANALYZE=true pnpm build