Building a Hugo Theme from Scratch Creating a custom Hugo theme has been an exciting journey! Here’s what I learned while building the nomad-tech theme.
Key Concepts Hugo’s template lookup order is crucial for theme development:
layouts/ ├── _default/ │ ├── baseof.html │ ├── list.html │ └── single.html ├── partials/ └── section-name/ └── list.html Hugo Pipes for Assets Modern Hugo themes should use Hugo Pipes for asset processing:
{{ $scss := resources.
CSS Grid vs Flexbox: When to Use What Understanding the differences between CSS Grid and Flexbox for modern layouts.
Use Flexbox For: One-dimensional layouts (rows OR columns) Component-level design Centering content Navigation bars Use CSS Grid For: Two-dimensional layouts (rows AND columns) Page-level design Complex layouts Card grids /* Flexbox for navigation */ .nav { display: flex; justify-content: space-between; align-items: center; } /* Grid for main layout */ .layout { display: grid; grid-template-columns: 1fr 3fr 1fr; grid-template-rows: auto 1fr auto; } Both are powerful tools - use them together!
Docker Development Workflow for Hugo Themes Setting up a consistent development environment across different machines is crucial for theme development. Here’s my Docker-based workflow.
The Setup FROM hugomods/hugo:exts-0.120.4 WORKDIR /src COPY . /src/themes/nomad-tech/ CMD ["hugo", "server", "--bind", "0.0.0.0", "--buildDrafts"] Docker Compose Configuration services: hugo: build: . volumes: - "./exampleSite:/src" ports: - "1313:1313" Benefits Consistency: Same Hugo version everywhere Security: Pinned, official images only Isolation: No local Hugo installation needed Portability: Works on any machine with Docker Development Commands # Start development server docker-compose up # Build for production docker-compose run hugo hugo --minify # Clean up docker-compose down This workflow has saved me countless hours of environment setup!
TypeScript Best Practices 2024 Essential TypeScript patterns and practices for better code quality.
Type Definitions // Use interfaces for object shapes interface User { id: string; name: string; email: string; createdAt: Date; } // Use type aliases for unions type Status = 'loading' | 'success' | 'error'; // Generic constraints interface Repository<T extends { id: string }> { findById(id: string): Promise<T>; save(entity: T): Promise<T>; } Utility Types // Partial for updates function updateUser(id: string, updates: Partial<User>) { // Implementation } // Pick for specific fields type UserSummary = Pick<User, 'id' | 'name'>; // Omit for exclusions type CreateUser = Omit<User, 'id' | 'createdAt'>; Best Practices Enable strict mode Use unknown instead of any Prefer type assertions over type casting Use const assertions for immutable data TypeScript makes JavaScript development so much safer!