Next.js 14 Developer Hub
Project Type: Personal Portfolio & Developer Hub
Tech Stack: Next.js 14, TypeScript, React 18, App Router
Deployment: Vercel
Status: Production
Overview
A modern, full-stack personal developer hub built with Next.js 14 App Router, featuring dynamic content management, multi-language support, and optimized performance. The platform serves as both a portfolio showcase and a technical knowledge base, demonstrating advanced Next.js patterns and best practices.
Architecture & Technical Decisions
Next.js 14 App Router
The project leverages Next.js 14's App Router architecture, providing:
- Server Components by Default: Most components are server-rendered, reducing client-side JavaScript bundle size
- File-based Routing: Automatic route generation from directory structure
- Nested Layouts: Shared layouts with
app/layout.tsxand route-specific layouts - Streaming & Suspense: Progressive page rendering for better perceived performance
Directory Structure:
app/
layout.tsx # Root layout with providers
page.tsx # Homepage (server component)
[slug]/ # Dynamic top-level routes
notes/[...slug]/ # Catch-all routes for nested content
personal/[...slug]/ # Personal section with nested routes
projects/[...slug]/ # Projects section with nested routes
api/ # API routes for dynamic content
Server vs Client Components
Server Components (default):
- Data fetching with
async/awaitdirectly in components - Access to Node.js APIs (
fs,path) - Zero client-side JavaScript for static content
- Example:
app/personal/[...slug]/page.tsx
export default async function Page({ params }: PageProps) { const language = getServerLanguage(); const basePath = buildContentPath('content', 'personal', ...slug); const result = await loadContent(basePath, language); if (result) { return <MDXRenderer source={result.content} /> } // Fallback logic... }
Client Components (explicit 'use client'):
- Interactive UI with React hooks
- Browser APIs and event handlers
- State management and context
- Example:
components/language/LanguageSwitcher.tsx
'use client'; export function LanguageSwitcher() { const { language, setLanguage } = useLanguage(); const router = useRouter(); const handleLanguageChange = (lang: Language) => { setLanguage(lang); router.refresh(); // Force server component re-render }; // ... }
Dynamic Routing & Content Management
Catch-All Routes
Implemented flexible routing using catch-all segments ([...slug]) to handle nested content hierarchies:
// app/notes/[...slug]/page.tsx export default async function Page({ params }: PageProps) { const { slug } = params; // ['frontend', 'react', 'hooks'] const urlPath = '/notes/' + slug.join('/'); const basePath = buildContentPath('content', 'notes', ...slug); // ... }
Benefits:
- Single route handler for unlimited nesting depth
- Automatic path resolution from URL segments
- Clean separation between routing and content structure
Content Loading with Language Fallback
Custom content loader with intelligent language fallback:
// lib/content-loader.ts export async function loadContent( basePath: string, language: Language ): Promise<{ content: string; language: string } | null> { const filePaths = getFilePaths(basePath, language); // Tries: index.{lang}.mdx -> {base}.{lang}.mdx -> fallback languages -> default return await tryLoadFile(filePaths); }
Fallback Strategy:
- Current language (folder format:
index.{lang}.mdx) - Current language (file format:
{name}.{lang}.mdx) - Fallback languages (EN → ZH_TW → ZH_CN)
- Default file (no language suffix)
Internationalization (i18n) Implementation
Client-Side Language Management
LanguageProvider context for client-side state:
// lib/i18n/LanguageProvider.tsx export function LanguageProvider({ children }) { const [language, setLanguageState] = useState<Language>(defaultLanguage); useEffect(() => { // 1. Check localStorage const savedLanguage = localStorage.getItem('language'); // 2. Detect browser language const browserLang = navigator.language; // 3. Set cookie for server-side access document.cookie = `language=${lang}; path=/; max-age=31536000`; }, []); }
Server-Side Language Detection
Server components read language from cookies:
// lib/i18n/server.ts export function getServerLanguage(): Language { const cookies = cookies(); const lang = cookies.get('language')?.value; return validateLanguage(lang) || defaultLanguage; }
Translation System
Modular translation structure with per-field multilingual objects:
// lib/i18n/translations/home.ts export const home = { welcome: { [LANGUAGE.ZH_TW]: '歡迎', [LANGUAGE.ZH_CN]: '欢迎', [LANGUAGE.EN]: 'Welcome', } as MultilangText, // ... };
Benefits:
- Type-safe translation keys
- Co-located translations with UI components
- Runtime language extraction with
extractLanguagehelper
MDX/Markdown Rendering System
Custom MDX Renderer
Built a custom renderer using react-markdown with enhanced features:
// components/mdx-renderer.tsx export default function MDXRenderer({ source }: MDXRendererProps) { return ( <ReactMarkdown remarkPlugins={[remarkGfm, remarkMath]} rehypePlugins={[rehypeKatex]} components={{ code: CodeBlock, // Syntax highlighting h1: Heading1, // Custom heading styles // ... custom components }} > {source} </ReactMarkdown> ); }
Features:
- Syntax Highlighting: Prism.js with VS Code Dark+ theme
- Math Support: KaTeX for mathematical expressions
- GFM Support: GitHub Flavored Markdown (tables, task lists)
- Custom Components: Styled headings, code blocks, links
Content Processing
Pre-processing pipeline for enhanced markdown features:
const processHighlight = (text: string) => { // Support <span class="highlight">highlight</span> syntax return text.replace(/==([^=]+)==/g, '<span class="highlight">$1</span>'); };
Performance Optimizations
Server Component Optimization
- Zero Client JS: Static content rendered server-side, no hydration needed
- Streaming: Progressive rendering with React Suspense
- Code Splitting: Automatic route-based code splitting
Build Optimizations
// next.config.js const nextConfig = { reactStrictMode: true, swcMinify: true, // Fast Rust-based minification experimental: { esmExternals: true, // ESM package support }, webpack: (config, { isServer }) => { // Exclude Node.js modules from client bundle if (!isServer) { config.resolve.fallback = { fs: false }; } return config; }, };
Image & Asset Optimization
- Next.js Image component for automatic optimization
- Font optimization with
next/font/google - Static asset optimization in build process
API Routes
RESTful API endpoints for dynamic content:
// app/api/notes/route.ts export async function GET() { const notesDirectory = path.join(process.cwd(), 'content', 'notes'); const files = await fs.readdir(notesDirectory); // Process and return structured data return NextResponse.json(notes); }
Type Safety & Developer Experience
TypeScript Configuration
- Strict type checking enabled
- Path aliases (
@/) for cleaner imports - Type definitions for all custom utilities
Component Patterns
- Consistent prop typing with interfaces
- Reusable utility functions (
cnfor class merging) - Error boundaries for graceful error handling
Deployment & CI/CD
- Vercel Integration: Automatic deployments from Git
- Environment Variables: Secure configuration management
- Build Optimization: Static generation where possible
- Edge Runtime: Optimized for global performance
Key Achievements
- 100% TypeScript: Full type safety across the codebase
- Multi-language Support: Seamless language switching with fallback
- Content Flexibility: File-based CMS with dynamic routing
- Performance: Fast initial load with server-side rendering
- Developer Experience: Clean architecture and maintainable code structure