2025-07-21 by Remi Kristelijn
This developer guide provides comprehensive information for developers who want to contribute to, extend, or maintain the Next.js blog. Whether you're adding new features, fixing bugs, or customizing the application, this guide will help you understand the codebase and development workflow.
# Clone the repository git clone <your-repo-url> cd next-blog # Install dependencies npm install # Start development server npm run dev
npm run dev # Start development server npm run build # Build for production npm run start # Start production server npm run lint # Run ESLint npm run type-check # Run TypeScript type checking npm run ci:build # Build for Cloudflare deployment
src/ ├── app/ # Next.js App Router pages ├── components/ # Reusable UI components ├── content/ # Blog content (MDX files) ├── lib/ # Utility functions and data layer └── types/ # TypeScript type definitions
src/app/layout.tsx: Root layout with theme and error boundarysrc/lib/posts.ts: Data layer for blog postssrc/types/index.ts: TypeScript interfacesnext.config.ts: Next.js configurationwrangler.jsonc: Cloudflare deployment configuration# Create a new branch git checkout -b feature/new-feature # Make your changes # Test locally with npm run dev # Commit your changes git add . git commit -m "feat: add new feature" # Push to remote git push origin feature/new-feature
Before submitting changes:
# Run type checking npm run type-check # Run linting npm run lint # Build the project npm run build
// src/components/NewComponent.tsx import { Box, Typography } from '@mui/material'; import type { NewComponentProps } from '@/types'; export default function NewComponent({ title, content }: NewComponentProps) { return ( <Box sx={{ p: 2 }}> <Typography variant="h6" gutterBottom> {title} </Typography> <Typography variant="body1"> {content} </Typography> </Box> ); }
// src/types/index.ts export interface NewComponentProps { title: string; content: string; optional?: boolean; }
src/content/posts/--- title: "Your Post Title" date: "YYYY-MM-DD" excerpt: "Brief description of your post" ---
// src/lib/posts.ts export function getPostsByCategory(category: string): Post[] { const allPosts = getAllPosts(); return allPosts.filter(post => post.category === category); } export function searchPosts(query: string): Post[] { const allPosts = getAllPosts(); return allPosts.filter(post => post.title.toLowerCase().includes(query.toLowerCase()) || post.content.toLowerCase().includes(query.toLowerCase()) ); }
// src/lib/theme.ts export const theme = createTheme({ palette: { primary: { main: '#1976d2', light: '#42a5f5', dark: '#1565c0', }, secondary: { main: '#dc004e', }, }, typography: { fontFamily: [ '-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Roboto', 'sans-serif', ].join(','), }, components: { MuiButton: { styleOverrides: { root: { textTransform: 'none', }, }, }, }, });
// src/components/Search.tsx import { useState } from 'react'; import { TextField, Box } from '@mui/material'; import { searchPosts } from '@/lib/posts'; export default function Search() { const [query, setQuery] = useState(''); const [results, setResults] = useState([]); const handleSearch = (value: string) => { setQuery(value); const searchResults = searchPosts(value); setResults(searchResults); }; return ( <Box> <TextField value={query} onChange={(e) => handleSearch(e.target.value)} placeholder="Search posts..." fullWidth /> {/* Display results */} </Box> ); }
// src/components/OptimizedImage.tsx import Image from 'next/image'; interface OptimizedImageProps { src: string; alt: string; width: number; height: number; } export default function OptimizedImage({ src, alt, width, height }: OptimizedImageProps) { return ( <Image src={src} alt={alt} width={width} height={height} placeholder="blur" blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k=" /> ); }
// src/app/about/page.tsx import { Container, Typography, Box } from '@mui/material'; import Navigation from '@/components/Navigation'; export default function AboutPage() { return ( <Box sx={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}> <Navigation title="About" showHome={true} showBack={false} /> <Container maxWidth="md" sx={{ flex: 1, py: 4 }}> <Typography variant="h3" component="h1" gutterBottom> About Us </Typography> <Typography variant="body1"> Your about page content here... </Typography> </Container> </Box> ); }
// __tests__/components/PostCard.test.tsx import { render, screen } from '@testing-library/react'; import PostCard from '@/components/PostCard'; const mockPost = { id: 'test-post', title: 'Test Post', excerpt: 'Test excerpt', date: '2024-01-25', slug: 'test-post', content: 'Test content', }; describe('PostCard', () => { it('renders post title and excerpt', () => { render(<PostCard post={mockPost} />); expect(screen.getByText('Test Post')).toBeInTheDocument(); expect(screen.getByText('Test excerpt')).toBeInTheDocument(); }); });
# Analyze bundle size npm run build # Check the .next/analyze directory for bundle analysis
// src/lib/performance.ts export function measurePerformance(name: string, fn: () => void) { const start = performance.now(); fn(); const end = performance.now(); console.log(`${name} took ${end - start} milliseconds`); }
# Build for production npm run build # Test production build npm run start
# Build for Cloudflare npm run ci:build # Deploy to Cloudflare Pages npm run deploy
# Clear Next.js cache rm -rf .next npm run build
# Check TypeScript configuration npx tsc --noEmit
# Clear npm cache npm cache clean --force rm -rf node_modules package-lock.json npm install
# Kill all Node processes pkill -f "next dev" npm run dev
This developer guide provides a comprehensive overview of how to contribute to and extend your Next.js blog. By following these guidelines, you can maintain code quality, add new features safely, and ensure the application continues to meet high standards of performance and accessibility.
Remember to:
The modular architecture and clear separation of concerns make it easy to add new features while maintaining the overall quality and performance of the application.
Happy coding! Your contributions help make the blog better for everyone.