PERFORMANCE OPTIMIZATIONS - nself-org/nchat GitHub Wiki
Version: 0.9.1 Date: February 9, 2026 Status: Implementation Ready
- Quick Start
- Lazy Loading
- Code Splitting
- Bundle Optimization
- Runtime Performance
- Database Optimization
- Monitoring
- Checklist
-
/Users/admin/Sites/nself-chat/src/lib/performance/lazy-loader.ts- Lazy loading utilities -
/Users/admin/Sites/nself-chat/src/lib/performance/performance-monitor.ts- Performance monitoring -
/Users/admin/Sites/nself-chat/.lighthouserc.js- Lighthouse CI configuration -
/Users/admin/Sites/nself-chat/scripts/analyze-bundle.ts- Bundle analysis script -
/Users/admin/Sites/nself-chat/docs/PERFORMANCE-AUDIT.md- Complete audit report -
/Users/admin/Sites/nself-chat/docs/BUNDLE-ANALYSIS.md- Bundle size analysis
# Analyze bundle sizes
pnpm build:analyze
# Run Lighthouse audit
pnpm lighthouse
# Generate bundle report
tsx scripts/analyze-bundle.ts
# Monitor performance in dev
# (automatically enabled via WebVitalsWrapper)Use the lazy loader utility for heavy components:
import {
LazyCallWindow,
LazyAdminDashboard,
LazyAnalyticsCharts,
LazyRichTextEditor,
LazyEmojiPicker,
} from '@/lib/performance/lazy-loader'
// Use in your component
function ChatPage() {
const [showEditor, setShowEditor] = useState(false)
return (
<div>
{showEditor ? (
<LazyRichTextEditor />
) : (
<button onClick={() => setShowEditor(true)}>
Start editing
</button>
)}
</div>
)
}Priority: 🔴 High (300KB savings)
File: /Users/admin/Sites/nself-chat/src/components/admin/analytics/charts.tsx
import { LazyAnalyticsCharts } from '@/lib/performance/lazy-loader'
export default function AdminAnalytics() {
return (
<div>
<h1>Analytics Dashboard</h1>
{/* Lazy load charts */}
<LazyAnalyticsCharts />
</div>
)
}Priority: 🔴 High (150KB savings)
File: /Users/admin/Sites/nself-chat/src/app/settings/privacy/gdpr/page.tsx
'use client'
import dynamic from 'next/dynamic'
const LazyGDPRTools = dynamic(
() => import('@/components/settings/privacy/gdpr-tools'),
{
loading: () => <div className="animate-pulse">Loading GDPR tools...</div>,
ssr: false,
}
)
export default function GDPRSettings() {
return (
<div>
<h1>GDPR & Data Privacy</h1>
<LazyGDPRTools />
</div>
)
}Priority: 🟡 Medium (150KB savings)
File: /Users/admin/Sites/nself-chat/src/components/chat/message-input.tsx
import { useState } from 'react'
import { LazyRichTextEditor } from '@/lib/performance/lazy-loader'
export function MessageInput() {
const [showRichEditor, setShowRichEditor] = useState(false)
return (
<div>
{showRichEditor ? (
<LazyRichTextEditor />
) : (
<textarea
onFocus={() => setShowRichEditor(true)}
placeholder="Type a message..."
/>
)}
</div>
)
}Priority: 🟡 Medium (80KB savings)
import { LazyEmojiPicker } from '@/lib/performance/lazy-loader'
function MessageActions() {
const [showEmoji, setShowEmoji] = useState(false)
return (
<>
<button onClick={() => setShowEmoji(true)}>😀</button>
{showEmoji && <LazyEmojiPicker onEmojiClick={handleEmoji} />}
</>
)
}Priority: 🟡 Medium (400KB savings)
import { LazyCallWindow } from '@/lib/performance/lazy-loader'
function Call({ callId }: { callId: string }) {
return <LazyCallWindow callId={callId} />
}Next.js automatically code splits by route. Ensure each route is in its own file:
src/app/
├── admin/
│ ├── page.tsx # Auto code split
│ ├── analytics/
│ │ └── page.tsx # Auto code split
│ └── moderation/
│ └── page.tsx # Auto code split
For shared components, use dynamic imports:
import dynamic from 'next/dynamic'
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <Skeleton />,
ssr: false,
})For large libraries used in specific features:
// Don't import at top level
// import recharts from 'recharts'
// Import dynamically when needed
async function renderChart() {
const { LineChart, Line, XAxis, YAxis } = await import('recharts')
// Use chart components
}Already configured in next.config.js:
experimental: {
optimizePackageImports: [
'lucide-react',
'@radix-ui/react-icons',
// ... more packages
]
}Ensure imports are tree-shakeable:
// ✅ Good - tree-shakeable
import { Button } from '@/components/ui/button'
// ❌ Bad - imports entire module
import * as UI from '@/components/ui'Run dependency analyzer:
npx depcheckUse the bundle analyzer:
ANALYZE=true pnpm buildThis will open a visual bundle analyzer in your browser.
Enable automatic monitoring:
import { startPerformanceMonitoring } from '@/lib/performance/performance-monitor'
// In _app.tsx or layout.tsx
useEffect(() => {
const cleanup = startPerformanceMonitoring({
memoryThreshold: 90,
reportInterval: 60000,
budgetCheck: true,
})
return cleanup
}, [])import { measureFunction } from '@/lib/performance/performance-monitor'
async function loadMessages() {
return measureFunction('load-messages', async () => {
const messages = await fetchMessages()
return messages
}, true) // true = log to console
}Use React Profiler:
import { Profiler } from 'react'
function onRenderCallback(
id: string,
phase: 'mount' | 'update',
actualDuration: number
) {
if (actualDuration > 16) { // Slower than 60fps
console.warn(`Slow render: ${id} took ${actualDuration}ms`)
}
}
function App() {
return (
<Profiler id="app" onRender={onRenderCallback}>
<YourApp />
</Profiler>
)
}Use React.memo for expensive components:
import { memo } from 'react'
const ExpensiveComponent = memo(function ExpensiveComponent({ data }) {
// Expensive rendering logic
return <div>{data}</div>
})
// Or with comparison function
const SmartComponent = memo(
function SmartComponent({ id, data }) {
return <div>{data}</div>
},
(prevProps, nextProps) => {
// Only re-render if id changes
return prevProps.id === nextProps.id
}
)import { useCallback, useMemo } from 'react'
function MessageList({ messages }) {
// Memoize expensive calculations
const sortedMessages = useMemo(() => {
return messages.sort((a, b) => b.timestamp - a.timestamp)
}, [messages])
// Memoize callbacks
const handleClick = useCallback((id: string) => {
console.log('Clicked:', id)
}, [])
return (
<div>
{sortedMessages.map(msg => (
<Message key={msg.id} onClick={handleClick} />
))}
</div>
)
}Already available at /Users/admin/Sites/nself-chat/src/lib/database/query-optimizer.ts
import { optimizeQuery } from '@/lib/database/query-optimizer'
const optimized = await optimizeQuery(yourQuery)Install and use DataLoader (already in dependencies):
import DataLoader from 'dataloader'
const userLoader = new DataLoader(async (ids: string[]) => {
const users = await db.users.findMany({
where: { id: { in: ids } }
})
// Return in same order as ids
return ids.map(id => users.find(u => u.id === id))
})
// Use in resolvers
const user = await userLoader.load(userId)Check slow queries:
-- PostgreSQL
SELECT * FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;Add indexes for slow queries:
CREATE INDEX idx_messages_channel_timestamp
ON nchat_messages(channel_id, created_at DESC);Already enabled in layout:
<WebVitalsWrapper
enabled={true}
providers={process.env.NODE_ENV === 'production' ? ['sentry'] : ['console']}
sampleRate={1.0}
/>Already configured. Verify environment variables:
# .env.local
NEXT_PUBLIC_SENTRY_DSN=your_dsn_here
SENTRY_AUTH_TOKEN=your_token_hereRun automated Lighthouse audits:
pnpm lighthouse:collect # Collect metrics
pnpm lighthouse:assert # Check budgets
pnpm lighthouse:upload # Upload resultsLog custom metrics to Sentry:
import * as Sentry from '@sentry/nextjs'
Sentry.setMeasurement('message_load_time', duration, 'millisecond')View metrics in:
- Sentry Performance Dashboard
- Lighthouse CI reports
- Browser DevTools Performance tab
- Create lazy-loader utility
- Create performance-monitor utility
- Configure Lighthouse CI
- Create bundle analysis script
- Lazy load Recharts in admin
- Lazy load GDPR tools
- Lazy load TipTap editor
- Lazy load emoji picker
- Code split admin routes
- Code split settings routes
- Implement DataLoader for GraphQL
- Add bundle size checks to CI/CD
- Set up performance alerts
- Optimize provider tree
- Implement service worker
- Regular performance audits
- Performance budgets enforcement
- Advanced caching strategies
- Edge function optimization
- CDN configuration
- Image optimization pipeline
| Resource | Current | Target | Priority |
|---|---|---|---|
| Shared Bundle | 103 KB | < 150 KB | ✅ Met |
| Public Pages | 104-221 KB | < 250 KB | ✅ Met |
| Chat Pages | 200-284 KB | < 300 KB | ✅ Met |
| Settings Pages | 466-478 KB | < 300 KB | 🔴 High |
| Admin Pages | 164-415 KB | < 350 KB | 🟡 Medium |
| Metric | Target | Status |
|---|---|---|
| LCP | < 2.5s | ✅ Monitored |
| FID | < 100ms | ✅ Monitored |
| CLS | < 0.1 | ✅ Monitored |
| TTI | < 3.5s | 🟡 Measure |
| FCP | < 1.8s | ✅ Monitored |
-
/Users/admin/Sites/nself-chat/docs/PERFORMANCE-AUDIT.md- Complete audit -
/Users/admin/Sites/nself-chat/docs/BUNDLE-ANALYSIS.md- Bundle analysis -
/Users/admin/Sites/nself-chat/src/lib/performance/lazy-loader.ts- Lazy loading -
/Users/admin/Sites/nself-chat/src/lib/performance/performance-monitor.ts- Monitoring -
/Users/admin/Sites/nself-chat/.lighthouserc.js- Lighthouse config
Last Updated: February 9, 2026 Next Review: March 9, 2026