Skip to content

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 components
2import dynamic from 'next/dynamic';
3 
4// Only load when needed
5const HeavyChart = dynamic(
6 () => import('@/components/HeavyChart'),
7 {
8 loading: () => <ChartSkeleton />,
9 ssr: false, // Skip SSR for client-only components
10 }
11);
12 
13// Use in component
14export function Dashboard() {
15 return (
16 <Suspense fallback={<ChartSkeleton />}>
17 <HeavyChart data={data} />
18 </Suspense>
19 );
20}
tsx
1// ❌ Bad: Animation on every item
2{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 only
8const 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 items
17{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.ts
2export default {
3 i18n: {
4 defaultLanguage: 'ko',
5 // Only load namespaces you need
6 namespaces: ['common', 'home'],
7 
8 // Preload critical namespaces
9 preloadNamespaces: ['common'],
10 
11 // Cache translations
12 cache: {
13 enabled: true,
14 maxAge: 1000 * 60 * 60, // 1 hour
15 },
16 },
17};
18 
19// Split translations by page
20// /translations/ko/home.json - only for home page
21// /translations/ko/dashboard.json - only for dashboard
tsx
1// next.config.js
2module.exports = {
3 // Enable SWC minification
4 swcMinify: true,
5 
6 // Optimize images
7 images: {
8 formats: ['image/avif', 'image/webp'],
9 },
10 
11 // Tree shake unused code
12 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 component
4const 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 calculations
13function Dashboard({ data }) {
14 const processedData = useMemo(() => {
15 return data.map(item => heavyCalculation(item));
16 }, [data]);
17 
18 // Memoize callbacks passed to children
19 const handleClick = useCallback((id) => {
20 console.log('clicked', id);
21 }, []);
22 
23 return <ExpensiveList items={processedData} onClick={handleClick} />;
24}
tsx
1// Respect user preferences
2import { 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 entirely
20function 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