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.tsx and 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/await directly 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:

  1. Current language (folder format: index.{lang}.mdx)
  2. Current language (file format: {name}.{lang}.mdx)
  3. Fallback languages (EN → ZH_TW → ZH_CN)
  4. 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 extractLanguage helper

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 (cn for 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