@zoyth/simple-site-framework 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +572 -0
- package/bin/create-simple-site.js +390 -0
- package/bin/simple-site.js +664 -0
- package/dist/client.js +135 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +107 -0
- package/dist/client.mjs.map +1 -0
- package/dist/components/index.d.mts +3936 -0
- package/dist/components/index.d.ts +3936 -0
- package/dist/components/index.js +38265 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/index.mjs +38173 -0
- package/dist/components/index.mjs.map +1 -0
- package/dist/config/index.d.mts +298 -0
- package/dist/config/index.d.ts +298 -0
- package/dist/config/index.js +19 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/index.mjs +1 -0
- package/dist/config/index.mjs.map +1 -0
- package/dist/index.d.mts +2184 -0
- package/dist/index.d.ts +2184 -0
- package/dist/index.js +1713 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1605 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib/i18n/index.js +665 -0
- package/dist/lib/i18n/index.js.map +1 -0
- package/dist/lib/i18n/index.mjs +621 -0
- package/dist/lib/i18n/index.mjs.map +1 -0
- package/docs/DOCUMENTATION-STRUCTURE.md +1156 -0
- package/docs/EXPORTS.md +125 -0
- package/docs/PERFORMANCE.md +757 -0
- package/docs/POLICY-PAGES.md +867 -0
- package/docs/ROADMAP.md +334 -0
- package/docs/SEO.md +455 -0
- package/docs/SITEMAP.md +708 -0
- package/docs/STRUCTURED-DATA.md +671 -0
- package/docs/accessibility/common-patterns.md +529 -0
- package/docs/accessibility/keyboard-navigation.md +263 -0
- package/docs/accessibility/overview.md +122 -0
- package/docs/accessibility/screen-readers.md +311 -0
- package/docs/accessibility/wcag-compliance.md +159 -0
- package/docs/api/README.md +164 -0
- package/docs/api/components/Accessibility.md +356 -0
- package/docs/api/components/Button.md +240 -0
- package/docs/api/components/HeroSection.md +306 -0
- package/docs/architecture/decisions.md +449 -0
- package/docs/components/AnalyticsTracker.md +58 -0
- package/docs/components/AnimatedCounter.md +48 -0
- package/docs/components/AnimatedSection.md +56 -0
- package/docs/components/BlogCard.md +42 -0
- package/docs/components/Checkbox.md +56 -0
- package/docs/components/CodeBlock.md +52 -0
- package/docs/components/ComparisonTable.md +40 -0
- package/docs/components/ComponentDemo.md +38 -0
- package/docs/components/CountdownTimer.md +51 -0
- package/docs/components/ExitIntentModal.md +56 -0
- package/docs/components/FAQAccordion.md +66 -0
- package/docs/components/FeaturesGrid.md +55 -0
- package/docs/components/FileUpload.md +54 -0
- package/docs/components/I18nMetaTags.md +55 -0
- package/docs/components/Icon.md +53 -0
- package/docs/components/LazySection.md +46 -0
- package/docs/components/LiveProof.md +53 -0
- package/docs/components/LoadingSpinner.md +46 -0
- package/docs/components/MultiStepForm.md +48 -0
- package/docs/components/PolicyLayout.md +55 -0
- package/docs/components/PricingTable.md +49 -0
- package/docs/components/Radio.md +59 -0
- package/docs/components/SEOMetaTags.md +58 -0
- package/docs/components/ScriptInjector.md +50 -0
- package/docs/components/Select.md +72 -0
- package/docs/components/Skeleton.md +47 -0
- package/docs/components/StatsSection.md +48 -0
- package/docs/components/StickyBar.md +62 -0
- package/docs/components/StructuredData.md +99 -0
- package/docs/components/StyleGuide.md +46 -0
- package/docs/components/TableOfContents.md +47 -0
- package/docs/components/TestimonialCarousel.md +42 -0
- package/docs/components/Timeline.md +51 -0
- package/docs/components/Toast.md +59 -0
- package/docs/components/TrackedLink.md +62 -0
- package/docs/components/TrustBadges.md +44 -0
- package/docs/components/conversion/MobileCTA.md +363 -0
- package/docs/components/forms/ContactForm.md +75 -0
- package/docs/components/forms/FormField.md +74 -0
- package/docs/components/layout/Footer.md +601 -0
- package/docs/components/layout/Header.md +549 -0
- package/docs/components/layout/LanguageSelector.md +54 -0
- package/docs/components/layout/LanguageSwitcher.md +24 -0
- package/docs/components/overview.md +447 -0
- package/docs/components/sections/AboutSection.md +48 -0
- package/docs/components/sections/CTASection.md +596 -0
- package/docs/components/sections/CaseStudySection.md +47 -0
- package/docs/components/sections/ContactSection.md +599 -0
- package/docs/components/sections/FeatureSection.md +44 -0
- package/docs/components/sections/HeroSection.md +404 -0
- package/docs/components/sections/LogosSection.md +47 -0
- package/docs/components/sections/PersonalTaxesSection.md +23 -0
- package/docs/components/sections/RecruitingSection.md +23 -0
- package/docs/components/sections/SecurePortalSection.md +23 -0
- package/docs/components/sections/ServicePageLayout.md +52 -0
- package/docs/components/sections/ServicesSection.md +49 -0
- package/docs/components/sections/TestimonialSection.md +44 -0
- package/docs/components/sections/WhyChooseUsSection.md +54 -0
- package/docs/components/ui/Breadcrumb.md +70 -0
- package/docs/components/ui/Button.md +514 -0
- package/docs/components/ui/Card.md +501 -0
- package/docs/components/ui/Input.md +54 -0
- package/docs/components/ui/MobileLinks.md +43 -0
- package/docs/components/ui/Modal.md +60 -0
- package/docs/components/ui/Tabs.md +62 -0
- package/docs/components/ui/Textarea.md +52 -0
- package/docs/core-concepts/configuration-driven.md +552 -0
- package/docs/core-concepts/overview.md +351 -0
- package/docs/features/accessibility/README.md +73 -0
- package/docs/features/accessibility/aria-support.md +177 -0
- package/docs/features/accessibility/color-contrast.md +155 -0
- package/docs/features/accessibility/focus-management.md +187 -0
- package/docs/features/accessibility/testing.md +196 -0
- package/docs/features/analytics/README.md +51 -0
- package/docs/features/analytics/ab-testing.md +171 -0
- package/docs/features/analytics/conversion-tracking.md +207 -0
- package/docs/features/analytics/custom-events.md +219 -0
- package/docs/features/analytics/privacy.md +198 -0
- package/docs/features/analytics/setup.md +114 -0
- package/docs/features/analytics/tracking-events.md +224 -0
- package/docs/features/i18n/README.md +51 -0
- package/docs/features/i18n/best-practices.md +273 -0
- package/docs/features/i18n/configuration.md +84 -0
- package/docs/features/i18n/formatting.md +133 -0
- package/docs/features/i18n/locale-detection.md +122 -0
- package/docs/features/i18n/routing.md +99 -0
- package/docs/features/i18n/rtl-support.md +191 -0
- package/docs/features/i18n/translations.md +129 -0
- package/docs/features/internationalization.md +595 -0
- package/docs/features/performance/README.md +77 -0
- package/docs/features/performance/bundle-size.md +134 -0
- package/docs/features/performance/caching.md +131 -0
- package/docs/features/performance/code-splitting.md +121 -0
- package/docs/features/performance/image-optimization.md +110 -0
- package/docs/features/performance/lazy-loading.md +92 -0
- package/docs/features/performance/monitoring.md +148 -0
- package/docs/features/seo/README.md +51 -0
- package/docs/features/seo/best-practices.md +184 -0
- package/docs/features/seo/canonical-urls.md +182 -0
- package/docs/features/seo/meta-tags.md +126 -0
- package/docs/features/seo/open-graph.md +166 -0
- package/docs/features/seo/robots-txt.md +146 -0
- package/docs/features/seo/sitemaps.md +162 -0
- package/docs/features/seo/structured-data.md +166 -0
- package/docs/getting-started/installation.md +292 -0
- package/docs/getting-started/introduction.md +195 -0
- package/docs/getting-started/quick-start.md +460 -0
- package/docs/guides/analytics-setup.md +616 -0
- package/docs/i18n/CONFIGURATION.md +353 -0
- package/docs/i18n/EXAMPLES.md +402 -0
- package/docs/i18n/MIGRATION.md +260 -0
- package/docs/i18n/SEO.md +392 -0
- package/docs/i18n/STATIC-GENERATION-FIX.md +71 -0
- package/docs/migration/changelog.md +136 -0
- package/docs/migration/overview.md +233 -0
- package/docs/recipes/adding-animations.md +475 -0
- package/docs/recipes/forms-with-validation.md +393 -0
- package/package.json +152 -0
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
# Performance Optimization Guide
|
|
2
|
+
|
|
3
|
+
This guide helps you build fast, high-converting websites using the simple-site-framework with optimal Next.js rendering strategies and performance best practices.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Rendering Strategies](#rendering-strategies)
|
|
8
|
+
2. [Image Optimization](#image-optimization)
|
|
9
|
+
3. [Bundle Size Optimization](#bundle-size-optimization)
|
|
10
|
+
4. [Core Web Vitals](#core-web-vitals)
|
|
11
|
+
5. [Framework-Specific Tips](#framework-specific-tips)
|
|
12
|
+
6. [Performance Monitoring](#performance-monitoring)
|
|
13
|
+
7. [Common Pitfalls](#common-pitfalls)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Rendering Strategies
|
|
18
|
+
|
|
19
|
+
Choose the right rendering strategy for each page to optimize both performance and SEO.
|
|
20
|
+
|
|
21
|
+
### When to use SSG (Static Site Generation) ✅ RECOMMENDED
|
|
22
|
+
|
|
23
|
+
**Best for:** Marketing pages, landing pages, blog posts, documentation
|
|
24
|
+
|
|
25
|
+
**Why:** Fastest possible load times, best SEO, lowest server costs
|
|
26
|
+
|
|
27
|
+
**Use cases:**
|
|
28
|
+
- Homepage (`/`)
|
|
29
|
+
- Features page (`/features`)
|
|
30
|
+
- Pricing page (`/pricing`)
|
|
31
|
+
- About page (`/about`)
|
|
32
|
+
- Blog posts (`/blog/[slug]`)
|
|
33
|
+
- Documentation (`/docs/[slug]`)
|
|
34
|
+
- Landing pages (`/lp/[campaign]`)
|
|
35
|
+
|
|
36
|
+
**Example:**
|
|
37
|
+
```typescript
|
|
38
|
+
// app/features/page.tsx
|
|
39
|
+
import { FeaturesSection } from 'simple-site-framework';
|
|
40
|
+
|
|
41
|
+
// This is a server component - rendered at build time
|
|
42
|
+
export default async function FeaturesPage() {
|
|
43
|
+
return (
|
|
44
|
+
<main>
|
|
45
|
+
<FeaturesSection
|
|
46
|
+
locale="en"
|
|
47
|
+
content={featuresContent}
|
|
48
|
+
/>
|
|
49
|
+
</main>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Force static generation
|
|
54
|
+
export const dynamic = 'force-static';
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Benefits:**
|
|
58
|
+
- ⚡ Instant page loads (served from CDN)
|
|
59
|
+
- 🔍 Perfect for SEO (HTML is pre-rendered)
|
|
60
|
+
- 💰 Lower hosting costs (no server compute per request)
|
|
61
|
+
- 📈 Better Core Web Vitals scores
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### When to use SSR (Server-Side Rendering)
|
|
66
|
+
|
|
67
|
+
**Best for:** Personalized content, frequently changing data, user-specific pages
|
|
68
|
+
|
|
69
|
+
**Use cases:**
|
|
70
|
+
- Dashboard pages (after authentication)
|
|
71
|
+
- User profile pages
|
|
72
|
+
- Dynamic pricing based on location/currency
|
|
73
|
+
- Real-time data displays
|
|
74
|
+
- A/B tested pages with server-side logic
|
|
75
|
+
|
|
76
|
+
**Example:**
|
|
77
|
+
```typescript
|
|
78
|
+
// app/dashboard/page.tsx
|
|
79
|
+
import { cookies } from 'next/headers';
|
|
80
|
+
|
|
81
|
+
// This runs on every request
|
|
82
|
+
export default async function DashboardPage() {
|
|
83
|
+
const userCookie = cookies().get('user');
|
|
84
|
+
const userData = await fetchUserData(userCookie);
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<main>
|
|
88
|
+
<h1>Welcome back, {userData.name}!</h1>
|
|
89
|
+
{/* Personalized content */}
|
|
90
|
+
</main>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Force dynamic rendering
|
|
95
|
+
export const dynamic = 'force-dynamic';
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**When to avoid SSR:**
|
|
99
|
+
- ⚠️ Static marketing pages (use SSG instead)
|
|
100
|
+
- ⚠️ High-traffic pages without personalization
|
|
101
|
+
- ⚠️ Pages that can be cached (use ISR instead)
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### When to use ISR (Incremental Static Regeneration)
|
|
106
|
+
|
|
107
|
+
**Best for:** Content that updates periodically but doesn't need to be real-time
|
|
108
|
+
|
|
109
|
+
**Use cases:**
|
|
110
|
+
- Blog index with new posts every few hours
|
|
111
|
+
- Product catalog that updates daily
|
|
112
|
+
- Pricing that changes occasionally
|
|
113
|
+
- Testimonials that are added monthly
|
|
114
|
+
|
|
115
|
+
**Example:**
|
|
116
|
+
```typescript
|
|
117
|
+
// app/blog/page.tsx
|
|
118
|
+
export const revalidate = 3600; // Revalidate every hour
|
|
119
|
+
|
|
120
|
+
export default async function BlogPage() {
|
|
121
|
+
const posts = await fetchBlogPosts();
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<main>
|
|
125
|
+
{posts.map(post => <BlogCard key={post.id} {...post} />)}
|
|
126
|
+
</main>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Benefits:**
|
|
132
|
+
- ⚡ Fast like SSG
|
|
133
|
+
- 🔄 Keeps content fresh
|
|
134
|
+
- 💰 Lower costs than SSR
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### When to use Client-Side Rendering (CSR)
|
|
139
|
+
|
|
140
|
+
**Best for:** Highly interactive features, real-time updates, authenticated areas
|
|
141
|
+
|
|
142
|
+
**Use cases:**
|
|
143
|
+
- Interactive calculators
|
|
144
|
+
- Real-time dashboards
|
|
145
|
+
- Chat interfaces
|
|
146
|
+
- Complex forms with multi-step logic
|
|
147
|
+
- After user actions (not for SEO-critical content)
|
|
148
|
+
|
|
149
|
+
**Example:**
|
|
150
|
+
```typescript
|
|
151
|
+
// components/PricingCalculator.tsx
|
|
152
|
+
'use client';
|
|
153
|
+
|
|
154
|
+
import { useState } from 'react';
|
|
155
|
+
|
|
156
|
+
export function PricingCalculator() {
|
|
157
|
+
const [users, setUsers] = useState(10);
|
|
158
|
+
const price = calculatePrice(users);
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<div>
|
|
162
|
+
<input
|
|
163
|
+
type="range"
|
|
164
|
+
value={users}
|
|
165
|
+
onChange={(e) => setUsers(Number(e.target.value))}
|
|
166
|
+
/>
|
|
167
|
+
<p>Price: ${price}/month</p>
|
|
168
|
+
</div>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**When to avoid CSR:**
|
|
174
|
+
- ❌ For SEO-critical content (won't be indexed)
|
|
175
|
+
- ❌ For above-the-fold content (bad LCP)
|
|
176
|
+
- ❌ For first-page impression content
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Image Optimization
|
|
181
|
+
|
|
182
|
+
Images are often the heaviest assets. Optimize them properly for fast loading.
|
|
183
|
+
|
|
184
|
+
### Always Use Next.js `<Image>`
|
|
185
|
+
|
|
186
|
+
**Why:** Automatic optimization, responsive sizing, lazy loading, format conversion (WebP/AVIF)
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import Image from 'next/image';
|
|
190
|
+
|
|
191
|
+
// ✅ GOOD - Optimized automatically
|
|
192
|
+
<Image
|
|
193
|
+
src="/hero-image.jpg"
|
|
194
|
+
alt="Email marketing dashboard"
|
|
195
|
+
width={1200}
|
|
196
|
+
height={600}
|
|
197
|
+
priority // For above-the-fold images
|
|
198
|
+
/>
|
|
199
|
+
|
|
200
|
+
// ❌ BAD - No optimization
|
|
201
|
+
<img src="/hero-image.jpg" alt="..." />
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Provide Width and Height
|
|
205
|
+
|
|
206
|
+
**Why:** Prevents Cumulative Layout Shift (CLS)
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
// ✅ GOOD - Prevents layout shift
|
|
210
|
+
<Image
|
|
211
|
+
src="/feature.jpg"
|
|
212
|
+
alt="Feature screenshot"
|
|
213
|
+
width={800}
|
|
214
|
+
height={600}
|
|
215
|
+
/>
|
|
216
|
+
|
|
217
|
+
// ⚠️ ACCEPTABLE - For dynamic aspect ratios
|
|
218
|
+
<div className="relative w-full aspect-video">
|
|
219
|
+
<Image
|
|
220
|
+
src="/feature.jpg"
|
|
221
|
+
alt="Feature screenshot"
|
|
222
|
+
fill
|
|
223
|
+
className="object-cover"
|
|
224
|
+
/>
|
|
225
|
+
</div>
|
|
226
|
+
|
|
227
|
+
// ❌ BAD - Will cause layout shift
|
|
228
|
+
<Image src="/feature.jpg" alt="..." />
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Use `priority` for Above-the-Fold Images
|
|
232
|
+
|
|
233
|
+
**Why:** Loads critical images immediately, improves LCP
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
// Hero image (visible on page load)
|
|
237
|
+
<Image
|
|
238
|
+
src="/hero.jpg"
|
|
239
|
+
alt="..."
|
|
240
|
+
width={1200}
|
|
241
|
+
height={600}
|
|
242
|
+
priority // ✅ Loads immediately
|
|
243
|
+
/>
|
|
244
|
+
|
|
245
|
+
// Below-the-fold image (not initially visible)
|
|
246
|
+
<Image
|
|
247
|
+
src="/feature-3.jpg"
|
|
248
|
+
alt="..."
|
|
249
|
+
width={800}
|
|
250
|
+
height={600}
|
|
251
|
+
// No priority - lazy loads when scrolled into view
|
|
252
|
+
/>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Optimize Image Sizes
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// Responsive images with sizes prop
|
|
259
|
+
<Image
|
|
260
|
+
src="/hero.jpg"
|
|
261
|
+
alt="..."
|
|
262
|
+
width={1200}
|
|
263
|
+
height={600}
|
|
264
|
+
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
265
|
+
/>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Framework Component Image Usage
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
// HeroSection - Mark background images as priority
|
|
272
|
+
<HeroSection
|
|
273
|
+
locale={locale}
|
|
274
|
+
content={{
|
|
275
|
+
...heroContent,
|
|
276
|
+
backgroundImage: '/hero-bg.jpg' // Will be optimized
|
|
277
|
+
}}
|
|
278
|
+
// No need to manually set priority - HeroSection does this
|
|
279
|
+
/>
|
|
280
|
+
|
|
281
|
+
// FeaturesSection - Icons lazy load automatically
|
|
282
|
+
<FeaturesSection
|
|
283
|
+
locale={locale}
|
|
284
|
+
content={featuresContent}
|
|
285
|
+
// Feature images automatically lazy-load
|
|
286
|
+
/>
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Bundle Size Optimization
|
|
292
|
+
|
|
293
|
+
Smaller bundles = faster downloads = better performance.
|
|
294
|
+
|
|
295
|
+
### Use Dynamic Imports for Heavy Components
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import dynamic from 'next/dynamic';
|
|
299
|
+
|
|
300
|
+
// ✅ GOOD - Loads only when needed
|
|
301
|
+
const HeavyChart = dynamic(() => import('./HeavyChart'), {
|
|
302
|
+
loading: () => <LoadingSpinner />,
|
|
303
|
+
ssr: false // Don't render on server if not needed
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// Use it conditionally
|
|
307
|
+
{showChart && <HeavyChart data={data} />}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Tree-Shake Framework Components
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// ✅ GOOD - Import only what you need
|
|
314
|
+
import { HeroSection, FeaturesSection } from 'simple-site-framework';
|
|
315
|
+
|
|
316
|
+
// ❌ BAD - Imports entire framework
|
|
317
|
+
import * as Framework from 'simple-site-framework';
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Analyze Bundle Size
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
# Install bundle analyzer
|
|
324
|
+
npm install --save-dev @next/bundle-analyzer
|
|
325
|
+
|
|
326
|
+
# Add to next.config.js
|
|
327
|
+
const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
|
328
|
+
enabled: process.env.ANALYZE === 'true',
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
module.exports = withBundleAnalyzer({
|
|
332
|
+
// your Next.js config
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
# Analyze
|
|
336
|
+
ANALYZE=true npm run build
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**What to look for:**
|
|
340
|
+
- Large third-party libraries (>100KB)
|
|
341
|
+
- Duplicate dependencies
|
|
342
|
+
- Unused code
|
|
343
|
+
- Framework components you're not using
|
|
344
|
+
|
|
345
|
+
### Avoid Importing Entire Libraries
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
// ❌ BAD - Imports all of lodash
|
|
349
|
+
import _ from 'lodash';
|
|
350
|
+
const result = _.debounce(fn, 300);
|
|
351
|
+
|
|
352
|
+
// ✅ GOOD - Imports only debounce
|
|
353
|
+
import debounce from 'lodash/debounce';
|
|
354
|
+
const result = debounce(fn, 300);
|
|
355
|
+
|
|
356
|
+
// ✅ BETTER - Use native or smaller alternatives
|
|
357
|
+
// lodash-es is tree-shakeable
|
|
358
|
+
import { debounce } from 'lodash-es';
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## Core Web Vitals
|
|
364
|
+
|
|
365
|
+
Google uses Core Web Vitals as ranking factors. Target these metrics:
|
|
366
|
+
|
|
367
|
+
### LCP (Largest Contentful Paint) - Target: < 2.5s
|
|
368
|
+
|
|
369
|
+
**What it measures:** How long until the main content is visible
|
|
370
|
+
|
|
371
|
+
**How to optimize:**
|
|
372
|
+
```typescript
|
|
373
|
+
// 1. Use priority for hero images
|
|
374
|
+
<Image src="/hero.jpg" priority width={1200} height={600} />
|
|
375
|
+
|
|
376
|
+
// 2. Avoid render-blocking scripts
|
|
377
|
+
<Script src="/analytics.js" strategy="afterInteractive" />
|
|
378
|
+
|
|
379
|
+
// 3. Use SSG for marketing pages
|
|
380
|
+
export const dynamic = 'force-static';
|
|
381
|
+
|
|
382
|
+
// 4. Optimize server response time
|
|
383
|
+
// - Use CDN for static assets
|
|
384
|
+
// - Enable HTTP/2
|
|
385
|
+
// - Compress responses (gzip/brotli)
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
**Framework tips:**
|
|
389
|
+
- HeroSection automatically optimizes hero images
|
|
390
|
+
- Use `backgroundEffect="none"` for fastest LCP if animations cause delays
|
|
391
|
+
- Avoid heavy animations in above-the-fold content
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
### FID (First Input Delay) - Target: < 100ms
|
|
396
|
+
|
|
397
|
+
**What it measures:** How quickly page responds to first user interaction
|
|
398
|
+
|
|
399
|
+
**How to optimize:**
|
|
400
|
+
```typescript
|
|
401
|
+
// 1. Minimize JavaScript execution
|
|
402
|
+
// Use dynamic imports for non-critical code
|
|
403
|
+
const Modal = dynamic(() => import('./Modal'));
|
|
404
|
+
|
|
405
|
+
// 2. Defer non-critical scripts
|
|
406
|
+
<Script src="/analytics.js" strategy="lazyOnload" />
|
|
407
|
+
|
|
408
|
+
// 3. Use code splitting
|
|
409
|
+
// Next.js does this automatically per route
|
|
410
|
+
|
|
411
|
+
// 4. Avoid long tasks
|
|
412
|
+
// Break up heavy computations
|
|
413
|
+
const result = useMemo(() => heavyCalculation(data), [data]);
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
### CLS (Cumulative Layout Shift) - Target: < 0.1
|
|
419
|
+
|
|
420
|
+
**What it measures:** How much content shifts during load
|
|
421
|
+
|
|
422
|
+
**How to optimize:**
|
|
423
|
+
```typescript
|
|
424
|
+
// 1. ALWAYS set image dimensions
|
|
425
|
+
<Image src="/logo.png" width={200} height={50} alt="Logo" />
|
|
426
|
+
|
|
427
|
+
// 2. Reserve space for ads/embeds
|
|
428
|
+
<div className="h-[250px] w-full">
|
|
429
|
+
<AdComponent />
|
|
430
|
+
</div>
|
|
431
|
+
|
|
432
|
+
// 3. Avoid injecting content above existing content
|
|
433
|
+
// Load ads/embeds at page load, not after
|
|
434
|
+
|
|
435
|
+
// 4. Use font-display: optional
|
|
436
|
+
// next/font does this automatically
|
|
437
|
+
import { Inter } from 'next/font/google';
|
|
438
|
+
const inter = Inter({ subsets: ['latin'] });
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
**Framework tips:**
|
|
442
|
+
- All framework images require width/height
|
|
443
|
+
- Modal/Dropdown animations don't cause CLS (position: fixed/absolute)
|
|
444
|
+
- ScrollIndicator renders after mount to avoid hydration CLS
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## Framework-Specific Tips
|
|
449
|
+
|
|
450
|
+
### HeroSection Performance
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
// ✅ Fastest configuration
|
|
454
|
+
<HeroSection
|
|
455
|
+
locale={locale}
|
|
456
|
+
content={heroContent}
|
|
457
|
+
animations={{ headline: 'fadeIn', cta: 'fadeIn' }} // Simple animations
|
|
458
|
+
backgroundEffect="none" // No heavy effects
|
|
459
|
+
stickyCtaAfterScroll={false} // Avoid scroll listener if not needed
|
|
460
|
+
/>
|
|
461
|
+
|
|
462
|
+
// ⚠️ Slower but more engaging
|
|
463
|
+
<HeroSection
|
|
464
|
+
locale={locale}
|
|
465
|
+
content={heroContent}
|
|
466
|
+
animations={{ headline: 'fadeInUp', cta: 'fadeInUp', scrollIndicator: true }}
|
|
467
|
+
backgroundEffect="gradient-shift" // Animated background
|
|
468
|
+
stickyCtaAfterScroll={true} // Scroll listener
|
|
469
|
+
/>
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
**Trade-offs:**
|
|
473
|
+
- Animations improve engagement but slightly delay FID
|
|
474
|
+
- Video backgrounds are heavy (use poster image for mobile)
|
|
475
|
+
- Sticky CTAs require scroll listeners (minimal perf impact)
|
|
476
|
+
|
|
477
|
+
### FeaturesSection Performance
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
// Features automatically lazy-load as you scroll
|
|
481
|
+
// No special optimization needed
|
|
482
|
+
|
|
483
|
+
// For very long feature lists:
|
|
484
|
+
<LazySection threshold={0.1}>
|
|
485
|
+
<FeaturesSection locale={locale} content={features} />
|
|
486
|
+
</LazySection>
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### TestimonialsSection Performance
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
// Carousel images lazy-load by default
|
|
493
|
+
// Limit to 6-8 testimonials for best performance
|
|
494
|
+
|
|
495
|
+
<TestimonialsSection
|
|
496
|
+
locale={locale}
|
|
497
|
+
content={testimonials.slice(0, 6)} // Limit for performance
|
|
498
|
+
/>
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### Analytics Performance
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
// ✅ Load after critical content
|
|
505
|
+
<Script
|
|
506
|
+
src="https://www.googletagmanager.com/gtag/js?id=GA_ID"
|
|
507
|
+
strategy="afterInteractive" // After page is interactive
|
|
508
|
+
/>
|
|
509
|
+
|
|
510
|
+
// AnalyticsTracker is lightweight and runs client-side only
|
|
511
|
+
<AnalyticsTracker />
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## Performance Monitoring
|
|
517
|
+
|
|
518
|
+
Track performance over time to catch regressions.
|
|
519
|
+
|
|
520
|
+
### Lighthouse CI
|
|
521
|
+
|
|
522
|
+
```bash
|
|
523
|
+
# Install
|
|
524
|
+
npm install --save-dev @lhci/cli
|
|
525
|
+
|
|
526
|
+
# Configure .lighthouserc.json
|
|
527
|
+
{
|
|
528
|
+
"ci": {
|
|
529
|
+
"collect": {
|
|
530
|
+
"numberOfRuns": 3,
|
|
531
|
+
"url": ["http://localhost:3000", "http://localhost:3000/features"]
|
|
532
|
+
},
|
|
533
|
+
"assert": {
|
|
534
|
+
"assertions": {
|
|
535
|
+
"categories:performance": ["error", {"minScore": 0.9}],
|
|
536
|
+
"categories:accessibility": ["error", {"minScore": 0.9}],
|
|
537
|
+
"categories:seo": ["error", {"minScore": 0.9}]
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
# Run in CI
|
|
544
|
+
npm run build && npm start
|
|
545
|
+
lhci autorun
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Next.js Analytics
|
|
549
|
+
|
|
550
|
+
If deploying to Vercel, enable built-in analytics:
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
// next.config.js
|
|
554
|
+
module.exports = {
|
|
555
|
+
experimental: {
|
|
556
|
+
webVitalsAttribution: ['CLS', 'LCP', 'FID'],
|
|
557
|
+
},
|
|
558
|
+
};
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
View real user metrics in Vercel dashboard.
|
|
562
|
+
|
|
563
|
+
### Chrome DevTools Performance Tab
|
|
564
|
+
|
|
565
|
+
1. Open DevTools → Performance
|
|
566
|
+
2. Click Record
|
|
567
|
+
3. Interact with page
|
|
568
|
+
4. Stop recording
|
|
569
|
+
5. Analyze timeline for:
|
|
570
|
+
- Long tasks (>50ms)
|
|
571
|
+
- Layout shifts
|
|
572
|
+
- Render-blocking resources
|
|
573
|
+
|
|
574
|
+
### WebPageTest
|
|
575
|
+
|
|
576
|
+
Test from real locations: https://www.webpagetest.org/
|
|
577
|
+
|
|
578
|
+
**What to check:**
|
|
579
|
+
- Time to First Byte (TTFB) < 600ms
|
|
580
|
+
- Start Render < 2s
|
|
581
|
+
- Fully Loaded < 5s
|
|
582
|
+
- Film strip for visual progress
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## Common Pitfalls
|
|
587
|
+
|
|
588
|
+
### ❌ Loading Too Many Fonts
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
// ❌ BAD - Multiple fonts and weights
|
|
592
|
+
import { Inter, Roboto, Poppins } from 'next/font/google';
|
|
593
|
+
const inter = Inter({ weight: ['300', '400', '500', '600', '700'] });
|
|
594
|
+
const roboto = Roboto({ weight: ['400', '700'] });
|
|
595
|
+
const poppins = Poppins({ weight: ['400', '600'] });
|
|
596
|
+
|
|
597
|
+
// ✅ GOOD - One font, essential weights
|
|
598
|
+
import { Inter } from 'next/font/google';
|
|
599
|
+
const inter = Inter({
|
|
600
|
+
subsets: ['latin'],
|
|
601
|
+
weight: ['400', '600'], // Regular and semibold only
|
|
602
|
+
display: 'swap',
|
|
603
|
+
});
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
**Impact:** Each font weight adds ~20-30KB. Limit to 2-3 weights max.
|
|
607
|
+
|
|
608
|
+
---
|
|
609
|
+
|
|
610
|
+
### ❌ Not Optimizing Images
|
|
611
|
+
|
|
612
|
+
```typescript
|
|
613
|
+
// ❌ BAD
|
|
614
|
+
<img src="/huge-image.png" alt="..." /> // 3MB PNG
|
|
615
|
+
|
|
616
|
+
// ✅ GOOD
|
|
617
|
+
<Image
|
|
618
|
+
src="/optimized-image.jpg" // Converted to WebP automatically
|
|
619
|
+
alt="..."
|
|
620
|
+
width={800}
|
|
621
|
+
height={600}
|
|
622
|
+
quality={85} // Good balance of quality/size
|
|
623
|
+
/>
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
**Impact:** Large images can delay LCP by seconds.
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
### ❌ Large Client-Side Bundles
|
|
631
|
+
|
|
632
|
+
```typescript
|
|
633
|
+
// ❌ BAD - Entire chart library loaded upfront
|
|
634
|
+
import { LineChart } from 'recharts';
|
|
635
|
+
|
|
636
|
+
export default function Page() {
|
|
637
|
+
return <LineChart data={data} />;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// ✅ GOOD - Loaded only when needed
|
|
641
|
+
import dynamic from 'next/dynamic';
|
|
642
|
+
|
|
643
|
+
const LineChart = dynamic(() => import('recharts').then(mod => mod.LineChart), {
|
|
644
|
+
ssr: false
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
export default function Page() {
|
|
648
|
+
return showChart ? <LineChart data={data} /> : <SkeletonChart />;
|
|
649
|
+
}
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**Impact:** Heavy libraries (>100KB) can delay FID.
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
### ❌ Blocking Third-Party Scripts
|
|
657
|
+
|
|
658
|
+
```typescript
|
|
659
|
+
// ❌ BAD - Blocks page rendering
|
|
660
|
+
<script src="https://example.com/widget.js"></script>
|
|
661
|
+
|
|
662
|
+
// ✅ GOOD - Loads asynchronously
|
|
663
|
+
<Script
|
|
664
|
+
src="https://example.com/widget.js"
|
|
665
|
+
strategy="afterInteractive"
|
|
666
|
+
/>
|
|
667
|
+
|
|
668
|
+
// ✅ BETTER - Loads after everything else
|
|
669
|
+
<Script
|
|
670
|
+
src="https://example.com/widget.js"
|
|
671
|
+
strategy="lazyOnload"
|
|
672
|
+
/>
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
**Impact:** Can delay FCP and LCP by 1-2 seconds.
|
|
676
|
+
|
|
677
|
+
---
|
|
678
|
+
|
|
679
|
+
### ❌ Not Using Memoization
|
|
680
|
+
|
|
681
|
+
```typescript
|
|
682
|
+
// ❌ BAD - Recalculates on every render
|
|
683
|
+
function ExpensiveComponent({ items }) {
|
|
684
|
+
const processed = items.map(heavyProcessing); // Runs every render
|
|
685
|
+
return <List items={processed} />;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// ✅ GOOD - Memoizes expensive calculations
|
|
689
|
+
function ExpensiveComponent({ items }) {
|
|
690
|
+
const processed = useMemo(
|
|
691
|
+
() => items.map(heavyProcessing),
|
|
692
|
+
[items]
|
|
693
|
+
);
|
|
694
|
+
return <List items={processed} />;
|
|
695
|
+
}
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
**Impact:** Can cause jank and poor FID.
|
|
699
|
+
|
|
700
|
+
---
|
|
701
|
+
|
|
702
|
+
## Performance Checklist
|
|
703
|
+
|
|
704
|
+
Use this checklist before deploying:
|
|
705
|
+
|
|
706
|
+
- [ ] All marketing pages use SSG
|
|
707
|
+
- [ ] Hero images have `priority` prop
|
|
708
|
+
- [ ] All images have width/height
|
|
709
|
+
- [ ] No images >200KB uncompressed
|
|
710
|
+
- [ ] Using next/font for web fonts
|
|
711
|
+
- [ ] Limited to 1-2 font families
|
|
712
|
+
- [ ] Scripts use `strategy="afterInteractive"` or `"lazyOnload"`
|
|
713
|
+
- [ ] Heavy components use dynamic imports
|
|
714
|
+
- [ ] Bundle analyzed (no massive chunks)
|
|
715
|
+
- [ ] Lighthouse score >90 for Performance
|
|
716
|
+
- [ ] LCP < 2.5s
|
|
717
|
+
- [ ] FID < 100ms
|
|
718
|
+
- [ ] CLS < 0.1
|
|
719
|
+
- [ ] No console errors or warnings
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
723
|
+
## Quick Reference
|
|
724
|
+
|
|
725
|
+
| Page Type | Rendering | Why |
|
|
726
|
+
|-----------|-----------|-----|
|
|
727
|
+
| Homepage | SSG | Fast, SEO-critical |
|
|
728
|
+
| Features | SSG | Static content, SEO-critical |
|
|
729
|
+
| Pricing | SSG or ISR | Mostly static, occasional updates |
|
|
730
|
+
| Blog Post | SSG or ISR | Static content, may add new posts |
|
|
731
|
+
| Blog Index | ISR | Updates with new posts |
|
|
732
|
+
| Dashboard | SSR | Personalized, authenticated |
|
|
733
|
+
| Calculator | CSR | Highly interactive |
|
|
734
|
+
| Documentation | SSG | Static, SEO-critical |
|
|
735
|
+
|
|
736
|
+
| Asset | Optimization |
|
|
737
|
+
|-------|--------------|
|
|
738
|
+
| Hero Image | `priority`, Next.js Image |
|
|
739
|
+
| Feature Icons | Lazy load, optimize SVG |
|
|
740
|
+
| Blog Images | Next.js Image, quality: 85 |
|
|
741
|
+
| Background Video | Poster image for mobile, lazy load |
|
|
742
|
+
| Fonts | next/font, 2 weights max |
|
|
743
|
+
| Scripts | `afterInteractive` or `lazyOnload` |
|
|
744
|
+
|
|
745
|
+
---
|
|
746
|
+
|
|
747
|
+
## Resources
|
|
748
|
+
|
|
749
|
+
- [Next.js Performance Docs](https://nextjs.org/docs/app/building-your-application/optimizing)
|
|
750
|
+
- [Web.dev Performance Guides](https://web.dev/performance/)
|
|
751
|
+
- [Core Web Vitals](https://web.dev/vitals/)
|
|
752
|
+
- [Lighthouse CI](https://github.com/GoogleChrome/lighthouse-ci)
|
|
753
|
+
- [WebPageTest](https://www.webpagetest.org/)
|
|
754
|
+
|
|
755
|
+
---
|
|
756
|
+
|
|
757
|
+
**Remember:** Performance is a feature. Fast sites convert better, rank higher, and provide better user experience. Monitor, measure, and optimize continuously.
|