refactor(ui): simplify empty state components and remove unused blog posts

- Replace custom SVG icons with lucide-react components in TaxonomyPageLayout, CategoryCard, and TagCard
- Remove unnecessary "Back to blog list" links from empty states
- Delete outdated blog posts about React Hooks, Docker, Tailwind CSS, and TypeScript
This commit is contained in:
joyzhao
2025-06-19 18:43:20 +08:00
parent 62364d1d11
commit 6c5813ecd2
11 changed files with 9 additions and 4632 deletions

View File

@@ -1,231 +0,0 @@
---
title: "Mastering React Hooks: A Deep Dive"
description: "Explore the power of React Hooks to manage state and side effects in functional components, with practical examples and best practices."
image: "https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=400&h=250&fit=crop&crop=center"
date: "May 10, 2025"
readTime: "5 min read"
tags: ["React", "JavaScript", "Frontend"]
tagId: ["react", "javascript", "frontend"]
category: ["React", "Frontend"]
categoryId: ["react", "frontend"]
slug: "mastering-react-hooks"
layout: "../../../layouts/BlogPostLayout.astro"
---
![React Hooks](https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=800&h=400&fit=crop&crop=center)
React Hooks have revolutionized the way we write React components, allowing us to use state and other React features in functional components. In this comprehensive guide, we'll explore the most important hooks and learn how to use them effectively.
## What are React Hooks?
React Hooks are functions that let you "hook into" React state and lifecycle features from functional components. They were introduced in React 16.8 and have since become the preferred way to write React components.
### Key Benefits:
- **Simpler code**: No need for class components
- **Better reusability**: Custom hooks allow sharing stateful logic
- **Easier testing**: Functional components are easier to test
- **Better performance**: Optimizations are easier to implement
## Essential React Hooks
### 1. useState Hook
The `useState` hook allows you to add state to functional components:
```javascript
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
```
### 2. useEffect Hook
The `useEffect` hook lets you perform side effects in functional components:
```javascript
import React, { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchUser() {
setLoading(true);
try {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
setUser(userData);
} catch (error) {
console.error('Error fetching user:', error);
} finally {
setLoading(false);
}
}
fetchUser();
}, [userId]); // Dependency array
if (loading) return <div>Loading...</div>;
if (!user) return <div>User not found</div>;
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}
```
### 3. useContext Hook
The `useContext` hook provides a way to pass data through the component tree without having to pass props down manually:
```javascript
import React, { useContext, createContext } from 'react';
const ThemeContext = createContext();
function App() {
return (
<ThemeContext.Provider value="dark">
<Header />
<Main />
</ThemeContext.Provider>
);
}
function Header() {
const theme = useContext(ThemeContext);
return (
<header className={`header-${theme}`}>
<h1>My App</h1>
</header>
);
}
```
## Custom Hooks
One of the most powerful features of React Hooks is the ability to create custom hooks that encapsulate and reuse stateful logic:
```javascript
// Custom hook for API calls
function useApi(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
setLoading(true);
const response = await fetch(url);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
fetchData();
}, [url]);
return { data, loading, error };
}
// Using the custom hook
function ProductList() {
const { data: products, loading, error } = useApi('/api/products');
if (loading) return <div>Loading products...</div>;
if (error) return <div>Error: {error}</div>;
return (
<ul>
{products.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
}
```
## Best Practices
### 1. Follow the Rules of Hooks
- Only call hooks at the top level of your React function
- Only call hooks from React functions (components or custom hooks)
### 2. Optimize Performance
Use `useMemo` and `useCallback` to prevent unnecessary re-renders:
```javascript
import React, { useMemo, useCallback } from 'react';
function ExpensiveComponent({ items, onItemClick }) {
// Memoize expensive calculations
const expensiveValue = useMemo(() => {
return items.reduce((sum, item) => sum + item.value, 0);
}, [items]);
// Memoize callback functions
const handleClick = useCallback((id) => {
onItemClick(id);
}, [onItemClick]);
return (
<div>
<p>Total: {expensiveValue}</p>
{items.map(item => (
<button key={item.id} onClick={() => handleClick(item.id)}>
{item.name}
</button>
))}
</div>
);
}
```
### 3. Clean Up Effects
Always clean up subscriptions and timers in useEffect:
```javascript
useEffect(() => {
const timer = setInterval(() => {
console.log('Timer tick');
}, 1000);
// Cleanup function
return () => {
clearInterval(timer);
};
}, []);
```
## Conclusion
React Hooks have fundamentally changed how we write React applications. They provide a more intuitive and powerful way to manage state and side effects in functional components. By mastering hooks like `useState`, `useEffect`, and `useContext`, and learning to create custom hooks, you'll be able to write more maintainable and reusable React code.
Remember to follow the rules of hooks, optimize for performance when necessary, and always clean up your effects. With these best practices in mind, you'll be well on your way to becoming a React Hooks expert!
---
*Want to learn more about React? Check out our other articles on advanced React patterns and performance optimization.*

View File

@@ -1,418 +0,0 @@
---
title: "Building Modern UIs with Tailwind CSS"
description: "Discover how to create beautiful, responsive user interfaces using Tailwind CSS utility classes and component patterns."
image: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&h=250&fit=crop&crop=center"
date: "April 15, 2025"
readTime: "6 min read"
tags: ["CSS", "Tailwind", "UI"]
slug: "modern-ui-tailwind"
layout: "../../../layouts/BlogPostLayout.astro"
---
![Modern UI Design](https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=800&h=400&fit=crop&crop=center)
Tailwind CSS has revolutionized the way developers approach styling web applications. By providing a comprehensive set of utility classes, it enables rapid development of beautiful, responsive user interfaces without writing custom CSS. Let's explore how to leverage Tailwind CSS to build modern UIs.
## Why Choose Tailwind CSS?
Tailwind CSS offers several advantages over traditional CSS frameworks:
- **Utility-first approach**: Build complex designs using simple utility classes
- **Highly customizable**: Configure every aspect of your design system
- **Responsive by default**: Built-in responsive design utilities
- **Performance optimized**: Only includes the CSS you actually use
- **Developer experience**: Excellent IntelliSense and tooling support
## Getting Started with Tailwind CSS
### Installation
Install Tailwind CSS in your project:
```bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```
Configure your `tailwind.config.js`:
```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{html,js,ts,jsx,tsx}",
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
primary: {
50: '#eff6ff',
500: '#3b82f6',
900: '#1e3a8a',
},
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
},
},
plugins: [],
}
```
Add Tailwind directives to your CSS:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
## Building Common UI Components
### 1. Modern Card Component
```html
<div class="max-w-sm mx-auto bg-white rounded-xl shadow-lg overflow-hidden md:max-w-2xl">
<div class="md:flex">
<div class="md:shrink-0">
<img class="h-48 w-full object-cover md:h-full md:w-48"
src="/api/placeholder/300/200"
alt="Modern architecture">
</div>
<div class="p-8">
<div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">
Company retreats
</div>
<a href="#" class="block mt-1 text-lg leading-tight font-medium text-black hover:underline">
Incredible accommodation for your team
</a>
<p class="mt-2 text-slate-500">
Looking to take your team away on a retreat to enjoy awesome food and take in some sunshine?
We have a list of places to do just that.
</p>
</div>
</div>
</div>
```
### 2. Responsive Navigation Bar
```html
<nav class="bg-white shadow-lg">
<div class="max-w-7xl mx-auto px-4">
<div class="flex justify-between h-16">
<div class="flex items-center">
<div class="flex-shrink-0">
<img class="h-8 w-8" src="/logo.svg" alt="Logo">
</div>
<div class="hidden md:block">
<div class="ml-10 flex items-baseline space-x-4">
<a href="#" class="text-gray-900 hover:text-gray-700 px-3 py-2 rounded-md text-sm font-medium">
Home
</a>
<a href="#" class="text-gray-500 hover:text-gray-700 px-3 py-2 rounded-md text-sm font-medium">
About
</a>
<a href="#" class="text-gray-500 hover:text-gray-700 px-3 py-2 rounded-md text-sm font-medium">
Services
</a>
<a href="#" class="text-gray-500 hover:text-gray-700 px-3 py-2 rounded-md text-sm font-medium">
Contact
</a>
</div>
</div>
</div>
<div class="hidden md:block">
<div class="ml-4 flex items-center md:ml-6">
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Get Started
</button>
</div>
</div>
<div class="md:hidden">
<button class="text-gray-500 hover:text-gray-600 focus:outline-none focus:text-gray-600">
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
</div>
</div>
</nav>
```
### 3. Modern Button Variants
```html
<!-- Primary Button -->
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition duration-300 ease-in-out transform hover:scale-105">
Primary Action
</button>
<!-- Secondary Button -->
<button class="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded transition duration-300">
Secondary Action
</button>
<!-- Gradient Button -->
<button class="bg-gradient-to-r from-purple-400 via-pink-500 to-red-500 hover:from-purple-600 hover:via-pink-600 hover:to-red-600 text-white font-bold py-3 px-6 rounded-full transition duration-300 ease-in-out transform hover:scale-105 shadow-lg">
Gradient Magic
</button>
<!-- Glass Morphism Button -->
<button class="backdrop-blur-sm bg-white/30 border border-white/20 rounded-xl px-6 py-3 text-white font-medium hover:bg-white/40 transition duration-300">
Glass Effect
</button>
```
## Advanced Layout Patterns
### 1. CSS Grid Dashboard
```html
<div class="min-h-screen bg-gray-100 p-4">
<div class="grid grid-cols-1 md:grid-cols-4 lg:grid-cols-6 gap-4 h-screen">
<!-- Sidebar -->
<aside class="bg-white rounded-lg shadow-md p-6 md:col-span-1 lg:col-span-1">
<h2 class="text-xl font-bold mb-4">Navigation</h2>
<nav class="space-y-2">
<a href="#" class="block p-2 rounded hover:bg-gray-100">Dashboard</a>
<a href="#" class="block p-2 rounded hover:bg-gray-100">Analytics</a>
<a href="#" class="block p-2 rounded hover:bg-gray-100">Settings</a>
</nav>
</aside>
<!-- Main Content -->
<main class="md:col-span-3 lg:col-span-4 space-y-4">
<!-- Header -->
<header class="bg-white rounded-lg shadow-md p-6">
<h1 class="text-2xl font-bold">Dashboard</h1>
</header>
<!-- Stats Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="bg-white rounded-lg shadow-md p-6">
<h3 class="text-lg font-semibold text-gray-700">Total Users</h3>
<p class="text-3xl font-bold text-blue-600">12,345</p>
</div>
<div class="bg-white rounded-lg shadow-md p-6">
<h3 class="text-lg font-semibold text-gray-700">Revenue</h3>
<p class="text-3xl font-bold text-green-600">$45,678</p>
</div>
<div class="bg-white rounded-lg shadow-md p-6">
<h3 class="text-lg font-semibold text-gray-700">Orders</h3>
<p class="text-3xl font-bold text-purple-600">1,234</p>
</div>
</div>
<!-- Chart Area -->
<div class="bg-white rounded-lg shadow-md p-6">
<h3 class="text-lg font-semibold mb-4">Analytics Chart</h3>
<div class="h-64 bg-gray-100 rounded flex items-center justify-center">
<p class="text-gray-500">Chart placeholder</p>
</div>
</div>
</main>
<!-- Right Sidebar -->
<aside class="bg-white rounded-lg shadow-md p-6 md:col-span-4 lg:col-span-1">
<h2 class="text-xl font-bold mb-4">Recent Activity</h2>
<div class="space-y-3">
<div class="flex items-center space-x-3">
<div class="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center">
<span class="text-white text-sm">JD</span>
</div>
<div>
<p class="text-sm font-medium">John Doe</p>
<p class="text-xs text-gray-500">2 minutes ago</p>
</div>
</div>
</div>
</aside>
</div>
</div>
```
### 2. Responsive Hero Section
```html
<section class="relative bg-gradient-to-r from-blue-600 to-purple-700 text-white">
<div class="absolute inset-0 bg-black opacity-50"></div>
<div class="relative max-w-7xl mx-auto px-4 py-24 sm:py-32">
<div class="text-center">
<h1 class="text-4xl sm:text-5xl md:text-6xl font-bold leading-tight mb-6">
Build Amazing
<span class="block text-transparent bg-clip-text bg-gradient-to-r from-yellow-400 to-pink-500">
User Experiences
</span>
</h1>
<p class="text-xl sm:text-2xl mb-8 max-w-3xl mx-auto leading-relaxed">
Create stunning, responsive websites with Tailwind CSS.
Fast, flexible, and beautifully designed.
</p>
<div class="flex flex-col sm:flex-row gap-4 justify-center">
<button class="bg-white text-blue-600 font-bold py-3 px-8 rounded-full hover:bg-gray-100 transition duration-300 transform hover:scale-105">
Get Started
</button>
<button class="border-2 border-white text-white font-bold py-3 px-8 rounded-full hover:bg-white hover:text-blue-600 transition duration-300">
Learn More
</button>
</div>
</div>
</div>
</section>
```
## Dark Mode Implementation
Tailwind CSS makes implementing dark mode straightforward:
```javascript
// tailwind.config.js
module.exports = {
darkMode: 'class', // or 'media'
// ... rest of config
}
```
```html
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white min-h-screen">
<header class="bg-gray-100 dark:bg-gray-800 p-4">
<h1 class="text-2xl font-bold">My App</h1>
<button id="theme-toggle" class="mt-2 p-2 rounded bg-gray-200 dark:bg-gray-700">
Toggle Theme
</button>
</header>
<main class="p-4">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6">
<h2 class="text-xl font-semibold mb-4">Content Card</h2>
<p class="text-gray-600 dark:text-gray-300">
This content adapts to both light and dark themes automatically.
</p>
</div>
</main>
</div>
```
```javascript
// Dark mode toggle script
const themeToggle = document.getElementById('theme-toggle');
const html = document.documentElement;
themeToggle.addEventListener('click', () => {
html.classList.toggle('dark');
localStorage.setItem('theme', html.classList.contains('dark') ? 'dark' : 'light');
});
// Load saved theme
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark') {
html.classList.add('dark');
}
```
## Performance Optimization
### 1. Purge Unused CSS
Tailwind automatically purges unused styles in production:
```javascript
// tailwind.config.js
module.exports = {
content: [
'./src/**/*.{html,js,ts,jsx,tsx}',
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
],
// This ensures only used classes are included
}
```
### 2. Custom Component Classes
For frequently used patterns, create component classes:
```css
@layer components {
.btn-primary {
@apply bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition duration-300;
}
.card {
@apply bg-white rounded-lg shadow-md p-6;
}
.input-field {
@apply w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500;
}
}
```
## Best Practices
### 1. Consistent Spacing Scale
Use Tailwind's spacing scale consistently:
```html
<!-- Good: Consistent spacing -->
<div class="p-4 mb-4">
<h2 class="text-xl mb-2">Title</h2>
<p class="mb-4">Content</p>
<button class="px-4 py-2">Action</button>
</div>
```
### 2. Responsive Design First
Always consider mobile-first design:
```html
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- Mobile: 1 column, Tablet: 2 columns, Desktop: 3 columns -->
</div>
```
### 3. Use Semantic Color Names
Define semantic colors in your config:
```javascript
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: '#3b82f6',
secondary: '#64748b',
success: '#10b981',
warning: '#f59e0b',
danger: '#ef4444',
},
},
},
}
```
## Conclusion
Tailwind CSS empowers developers to build modern, responsive UIs quickly and efficiently. By leveraging its utility-first approach, you can:
- Rapidly prototype and iterate on designs
- Maintain consistent design systems
- Build responsive layouts with ease
- Implement dark mode effortlessly
- Optimize for performance automatically
The key to mastering Tailwind CSS is understanding its utility classes and learning to compose them effectively. Start with simple components and gradually build more complex layouts as you become comfortable with the framework.
Remember to customize your Tailwind configuration to match your design system and always consider performance implications when building for production.
---
*Want to dive deeper? Explore our advanced guide on building design systems with Tailwind CSS and component libraries.*

View File

@@ -1,398 +0,0 @@
---
title: "Scaling Node.js Apps with Docker"
description: "Learn how to containerize Node.js applications using Docker for seamless deployment and scalability in production environments."
image: "https://images.unsplash.com/photo-1605745341112-85968b19335b?w=400&h=250&fit=crop&crop=center"
date: "April 25, 2025"
readTime: "7 min read"
tags: ["Node.js", "Docker", "DevOps"]
slug: "scaling-nodejs-docker"
layout: "../../../layouts/BlogPostLayout.astro"
---
![Docker and Node.js](https://images.unsplash.com/photo-1605745341112-85968b19335b?w=800&h=400&fit=crop&crop=center)
Docker has revolutionized how we deploy and scale applications. When combined with Node.js, it provides a powerful platform for building scalable, maintainable applications. In this guide, we'll explore how to containerize Node.js applications and scale them effectively.
## Why Docker for Node.js?
Docker offers several advantages for Node.js applications:
- **Consistency**: Same environment across development, testing, and production
- **Isolation**: Applications run in isolated containers
- **Scalability**: Easy horizontal scaling with container orchestration
- **Portability**: Run anywhere Docker is supported
- **Resource efficiency**: Lightweight compared to virtual machines
## Creating a Dockerfile for Node.js
Let's start with a basic Node.js application and create a Dockerfile:
```dockerfile
# Use the official Node.js runtime as the base image
FROM node:18-alpine
# Set the working directory inside the container
WORKDIR /usr/src/app
# Copy package.json and package-lock.json (if available)
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy the rest of the application code
COPY . .
# Create a non-root user to run the application
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# Change ownership of the app directory to the nodejs user
RUN chown -R nextjs:nodejs /usr/src/app
USER nextjs
# Expose the port the app runs on
EXPOSE 3000
# Define the command to run the application
CMD ["node", "server.js"]
```
## Multi-Stage Builds for Optimization
For production applications, use multi-stage builds to reduce image size:
```dockerfile
# Build stage
FROM node:18-alpine AS builder
WORKDIR /usr/src/app
# Copy package files
COPY package*.json ./
# Install all dependencies (including devDependencies)
RUN npm ci
# Copy source code
COPY . .
# Build the application (if you have a build step)
RUN npm run build
# Production stage
FROM node:18-alpine AS production
WORKDIR /usr/src/app
# Copy package files
COPY package*.json ./
# Install only production dependencies
RUN npm ci --only=production && npm cache clean --force
# Copy built application from builder stage
COPY --from=builder /usr/src/app/dist ./dist
COPY --from=builder /usr/src/app/server.js ./
# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
RUN chown -R nextjs:nodejs /usr/src/app
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]
```
## Docker Compose for Development
Use Docker Compose to manage your development environment:
```yaml
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
environment:
- NODE_ENV=development
- DATABASE_URL=mongodb://mongo:27017/myapp
depends_on:
- mongo
- redis
command: npm run dev
mongo:
image: mongo:5.0
ports:
- "27017:27017"
volumes:
- mongo_data:/data/db
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
mongo_data:
redis_data:
```
## Production Deployment with Docker Swarm
For production scaling, use Docker Swarm or Kubernetes. Here's a Docker Swarm example:
```yaml
# docker-compose.prod.yml
version: '3.8'
services:
app:
image: myapp:latest
deploy:
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=mongodb://mongo:27017/myapp
networks:
- app-network
depends_on:
- mongo
mongo:
image: mongo:5.0
deploy:
replicas: 1
restart_policy:
condition: on-failure
volumes:
- mongo_data:/data/db
networks:
- app-network
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
nginx:
image: nginx:alpine
deploy:
replicas: 1
restart_policy:
condition: on-failure
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
networks:
- app-network
depends_on:
- app
volumes:
mongo_data:
external: true
networks:
app-network:
driver: overlay
```
## Health Checks and Monitoring
Add health checks to your Dockerfile:
```dockerfile
# Add to your Dockerfile
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node healthcheck.js
```
Create a simple health check script:
```javascript
// healthcheck.js
const http = require('http');
const options = {
host: 'localhost',
port: 3000,
path: '/health',
timeout: 2000
};
const request = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
if (res.statusCode === 200) {
process.exit(0);
} else {
process.exit(1);
}
});
request.on('error', (err) => {
console.log('ERROR:', err);
process.exit(1);
});
request.end();
```
## Performance Optimization Tips
### 1. Use .dockerignore
Create a `.dockerignore` file to exclude unnecessary files:
```
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
.cache
```
### 2. Optimize Layer Caching
Order your Dockerfile commands to maximize cache efficiency:
```dockerfile
# Copy package files first (changes less frequently)
COPY package*.json ./
RUN npm ci --only=production
# Copy source code last (changes more frequently)
COPY . .
```
### 3. Use Alpine Images
Alpine Linux images are much smaller:
```dockerfile
FROM node:18-alpine # ~40MB
# vs
FROM node:18 # ~350MB
```
### 4. Implement Graceful Shutdown
```javascript
// server.js
const express = require('express');
const app = express();
const server = require('http').createServer(app);
// Your app routes here
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.get('/health', (req, res) => {
res.status(200).send('OK');
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('SIGTERM received, shutting down gracefully');
server.close(() => {
console.log('Process terminated');
process.exit(0);
});
});
process.on('SIGINT', () => {
console.log('SIGINT received, shutting down gracefully');
server.close(() => {
console.log('Process terminated');
process.exit(0);
});
});
```
## Monitoring and Logging
Use structured logging and monitoring:
```javascript
// logger.js
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
)
})
]
});
module.exports = logger;
```
## Conclusion
Docker provides a powerful platform for scaling Node.js applications. By following these best practices:
- Use multi-stage builds for optimized production images
- Implement proper health checks and graceful shutdown
- Use Docker Compose for development environments
- Leverage orchestration tools like Docker Swarm or Kubernetes for production
- Monitor and log your applications properly
You'll be able to build robust, scalable Node.js applications that can handle production workloads efficiently.
Remember that containerization is just one part of a scalable architecture. Consider implementing load balancing, caching strategies, and database optimization for complete scalability.
---
*Ready to deploy? Check out our guide on Kubernetes deployment strategies for even more advanced scaling techniques.*

View File

@@ -1,575 +0,0 @@
---
title: "TypeScript Best Practices for Large Projects"
description: "Essential TypeScript patterns and practices for maintaining code quality and developer productivity in enterprise applications."
image: "https://images.unsplash.com/photo-1516321318423-f06f85e504b3?w=400&h=250&fit=crop&crop=center"
date: "March 30, 2025"
readTime: "8 min read"
tags: ["TypeScript", "JavaScript", "Architecture"]
slug: "typescript-best-practices"
layout: "../../../layouts/BlogPostLayout.astro"
---
![TypeScript Development](https://images.unsplash.com/photo-1516321318423-f06f85e504b3?w=800&h=400&fit=crop&crop=center)
TypeScript has become the de facto standard for building large-scale JavaScript applications. Its static type system helps catch errors early, improves code maintainability, and enhances developer productivity. In this comprehensive guide, we'll explore essential TypeScript best practices for enterprise-level projects.
## Why TypeScript for Large Projects?
TypeScript offers significant advantages for large codebases:
- **Static Type Checking**: Catch errors at compile time rather than runtime
- **Enhanced IDE Support**: Better autocomplete, refactoring, and navigation
- **Self-Documenting Code**: Types serve as inline documentation
- **Safer Refactoring**: Confidence when making changes across large codebases
- **Team Collaboration**: Clear contracts between different parts of the application
## Project Structure and Configuration
### 1. TypeScript Configuration
Start with a robust `tsconfig.json`:
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "node",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"allowJs": false,
"checkJs": false,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"removeComments": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"noImplicitOverride": true,
"allowUnusedLabels": false,
"allowUnreachableCode": false,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@/components/*": ["src/components/*"],
"@/utils/*": ["src/utils/*"],
"@/types/*": ["src/types/*"]
}
},
"include": [
"src/**/*",
"tests/**/*"
],
"exclude": [
"node_modules",
"dist",
"**/*.js"
]
}
```
### 2. Project Structure
Organize your project for scalability:
```markdown
src/
├── components/ # Reusable UI components
│ ├── common/ # Shared components
│ └── feature/ # Feature-specific components
├── hooks/ # Custom React hooks
├── services/ # API and external service integrations
├── stores/ # State management
├── types/ # Type definitions
│ ├── api.ts # API response types
│ ├── common.ts # Common utility types
│ └── domain.ts # Business domain types
├── utils/ # Utility functions
├── constants/ # Application constants
└── __tests__/ # Test files
```
## Type Definition Best Practices
### 1. Use Interfaces for Object Shapes
```typescript
// Good: Use interfaces for object contracts
interface User {
readonly id: string;
name: string;
email: string;
createdAt: Date;
updatedAt: Date;
preferences?: UserPreferences;
}
interface UserPreferences {
theme: 'light' | 'dark';
notifications: boolean;
language: string;
}
// Good: Extend interfaces for related types
interface AdminUser extends User {
permissions: Permission[];
lastLogin: Date;
}
```
### 2. Use Type Aliases for Unions and Complex Types
```typescript
// Good: Use type aliases for unions
type Status = 'pending' | 'approved' | 'rejected' | 'cancelled';
type Theme = 'light' | 'dark' | 'auto';
// Good: Use type aliases for complex computed types
type ApiResponse<T> = {
data: T;
status: number;
message: string;
timestamp: string;
};
// Good: Use mapped types for transformations
type PartialUser = Partial<User>;
type UserKeys = keyof User;
type RequiredUserFields = Required<Pick<User, 'id' | 'name' | 'email'>>;
```
### 3. Create Discriminated Unions for State Management
```typescript
// Good: Discriminated unions for different states
type LoadingState = {
status: 'loading';
progress?: number;
};
type SuccessState = {
status: 'success';
data: User[];
};
type ErrorState = {
status: 'error';
error: string;
retryCount: number;
};
type AsyncState = LoadingState | SuccessState | ErrorState;
// Usage with type guards
function handleState(state: AsyncState) {
switch (state.status) {
case 'loading':
return `Loading... ${state.progress || 0}%`;
case 'success':
return `Loaded ${state.data.length} users`;
case 'error':
return `Error: ${state.error} (Retry: ${state.retryCount})`;
}
}
```
## Advanced Type Patterns
### 1. Generic Constraints and Conditional Types
```typescript
// Generic constraints
interface Identifiable {
id: string;
}
function updateEntity<T extends Identifiable>(
entity: T,
updates: Partial<Omit<T, 'id'>>
): T {
return { ...entity, ...updates };
}
// Conditional types
type ApiEndpoint<T> = T extends 'users'
? '/api/users'
: T extends 'posts'
? '/api/posts'
: never;
// Utility type for API responses
type InferApiResponse<T> = T extends (args: any) => Promise<infer R>
? R
: never;
```
### 2. Template Literal Types
```typescript
// Template literal types for type-safe routing
type Route = '/users' | '/posts' | '/settings';
type DynamicRoute = `/users/${string}` | `/posts/${string}`;
type AllRoutes = Route | DynamicRoute;
// Type-safe event handling
type EventType = 'click' | 'hover' | 'focus';
type ElementType = 'button' | 'input' | 'div';
type EventHandler = `on${Capitalize<EventType>}${Capitalize<ElementType>}`;
// Usage
const handlers: Record<EventHandler, () => void> = {
onClickButton: () => console.log('Button clicked'),
onHoverDiv: () => console.log('Div hovered'),
// TypeScript will enforce all combinations exist
};
```
### 3. Branded Types for Type Safety
```typescript
// Branded types to prevent mixing similar types
type UserId = string & { readonly brand: unique symbol };
type PostId = string & { readonly brand: unique symbol };
type Email = string & { readonly brand: unique symbol };
// Factory functions
function createUserId(id: string): UserId {
// Add validation logic here
if (!id || id.length < 3) {
throw new Error('Invalid user ID');
}
return id as UserId;
}
function createEmail(email: string): Email {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
throw new Error('Invalid email format');
}
return email as Email;
}
// Usage - prevents accidental mixing
function getUser(id: UserId): Promise<User> {
// Implementation
}
function getPost(id: PostId): Promise<Post> {
// Implementation
}
// This would cause a TypeScript error:
// getUser(postId); // Error: PostId is not assignable to UserId
```
## Error Handling Patterns
### 1. Result Type Pattern
```typescript
// Result type for better error handling
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
// Utility functions
function success<T>(data: T): Result<T> {
return { success: true, data };
}
function failure<E>(error: E): Result<never, E> {
return { success: false, error };
}
// Usage in async functions
async function fetchUser(id: UserId): Promise<Result<User, string>> {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
return failure(`HTTP ${response.status}: ${response.statusText}`);
}
const user = await response.json();
return success(user);
} catch (error) {
return failure(error instanceof Error ? error.message : 'Unknown error');
}
}
// Type-safe error handling
async function handleUserFetch(id: UserId) {
const result = await fetchUser(id);
if (result.success) {
console.log('User:', result.data.name); // TypeScript knows data exists
} else {
console.error('Error:', result.error); // TypeScript knows error exists
}
}
```
### 2. Custom Error Classes
```typescript
// Base error class
abstract class AppError extends Error {
abstract readonly code: string;
abstract readonly statusCode: number;
constructor(message: string, public readonly context?: Record<string, unknown>) {
super(message);
this.name = this.constructor.name;
}
}
// Specific error types
class ValidationError extends AppError {
readonly code = 'VALIDATION_ERROR';
readonly statusCode = 400;
}
class NotFoundError extends AppError {
readonly code = 'NOT_FOUND';
readonly statusCode = 404;
}
class DatabaseError extends AppError {
readonly code = 'DATABASE_ERROR';
readonly statusCode = 500;
}
// Type guard for error handling
function isAppError(error: unknown): error is AppError {
return error instanceof AppError;
}
// Usage
try {
// Some operation
} catch (error) {
if (isAppError(error)) {
console.error(`${error.code}: ${error.message}`, error.context);
} else {
console.error('Unexpected error:', error);
}
}
```
## API Integration Patterns
### 1. Type-Safe API Client
```typescript
// API endpoint definitions
interface ApiEndpoints {
'GET /users': {
response: User[];
};
'GET /users/:id': {
params: { id: UserId };
response: User;
};
'POST /users': {
body: CreateUserRequest;
response: User;
};
'PUT /users/:id': {
params: { id: UserId };
body: UpdateUserRequest;
response: User;
};
}
// Generic API client
class ApiClient {
private baseUrl: string;
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
async request<K extends keyof ApiEndpoints>(
endpoint: K,
options?: {
params?: ApiEndpoints[K] extends { params: infer P } ? P : never;
body?: ApiEndpoints[K] extends { body: infer B } ? B : never;
}
): Promise<ApiEndpoints[K] extends { response: infer R } ? R : never> {
// Implementation details
const url = this.buildUrl(endpoint, options?.params);
const response = await fetch(url, {
method: this.getMethod(endpoint),
headers: { 'Content-Type': 'application/json' },
body: options?.body ? JSON.stringify(options.body) : undefined,
});
if (!response.ok) {
throw new Error(`API Error: ${response.status}`);
}
return response.json();
}
private buildUrl(endpoint: string, params?: Record<string, string>): string {
let url = endpoint;
if (params) {
Object.entries(params).forEach(([key, value]) => {
url = url.replace(`:${key}`, value);
});
}
return `${this.baseUrl}${url}`;
}
private getMethod(endpoint: string): string {
return endpoint.split(' ')[0];
}
}
// Usage
const api = new ApiClient('https://api.example.com');
// Type-safe API calls
const users = await api.request('GET /users');
const user = await api.request('GET /users/:id', { params: { id: userId } });
const newUser = await api.request('POST /users', { body: createUserData });
```
## Testing Patterns
### 1. Type-Safe Test Utilities
```typescript
// Test data factories
interface TestDataFactory<T> {
build(overrides?: Partial<T>): T;
buildList(count: number, overrides?: Partial<T>): T[];
}
function createFactory<T>(defaultData: T): TestDataFactory<T> {
return {
build: (overrides = {}) => ({ ...defaultData, ...overrides }),
buildList: (count, overrides = {}) =>
Array.from({ length: count }, () => ({ ...defaultData, ...overrides }))
};
}
// Usage
const userFactory = createFactory<User>({
id: createUserId('test-user-1'),
name: 'Test User',
email: createEmail('test@example.com'),
createdAt: new Date(),
updatedAt: new Date(),
});
// In tests
const testUser = userFactory.build({ name: 'Custom Name' });
const testUsers = userFactory.buildList(5);
```
### 2. Mock Type Utilities
```typescript
// Utility types for mocking
type MockedFunction<T extends (...args: any[]) => any> = jest.MockedFunction<T>;
type MockedClass<T> = jest.Mocked<T>;
// Partial mocking utility
type PartialMock<T> = {
[K in keyof T]?: T[K] extends (...args: any[]) => any
? MockedFunction<T[K]>
: T[K];
};
// Create typed mocks
function createMock<T>(overrides: PartialMock<T> = {}): jest.Mocked<T> {
return overrides as jest.Mocked<T>;
}
// Usage
const mockUserService = createMock<UserService>({
getUser: jest.fn().mockResolvedValue(testUser),
createUser: jest.fn().mockResolvedValue(testUser),
});
```
## Performance Optimization
### 1. Lazy Loading with Types
```typescript
// Lazy component loading
const LazyUserProfile = React.lazy(() =>
import('./UserProfile').then(module => ({ default: module.UserProfile }))
);
// Type-safe dynamic imports
type ComponentModule<T> = {
default: React.ComponentType<T>;
};
async function loadComponent<T>(
importFn: () => Promise<ComponentModule<T>>
): Promise<React.ComponentType<T>> {
const module = await importFn();
return module.default;
}
```
### 2. Optimized Bundle Splitting
```typescript
// Feature-based code splitting
export const UserFeature = {
UserList: React.lazy(() => import('./UserList')),
UserProfile: React.lazy(() => import('./UserProfile')),
UserSettings: React.lazy(() => import('./UserSettings')),
};
// Route-based splitting
export const Routes = {
Home: React.lazy(() => import('../pages/Home')),
Users: React.lazy(() => import('../pages/Users')),
Settings: React.lazy(() => import('../pages/Settings')),
} as const;
```
## Conclusion
Implementing these TypeScript best practices in large projects will:
- **Improve Code Quality**: Catch errors early and enforce consistent patterns
- **Enhance Developer Experience**: Better IDE support and refactoring capabilities
- **Increase Maintainability**: Self-documenting code and clear contracts
- **Boost Team Productivity**: Shared understanding through types
- **Reduce Runtime Errors**: Comprehensive compile-time checking
### Key Takeaways:
1. **Start with strict TypeScript configuration** for maximum type safety
2. **Use discriminated unions** for complex state management
3. **Implement branded types** for domain-specific type safety
4. **Create type-safe API clients** to prevent integration errors
5. **Establish consistent error handling patterns** with Result types
6. **Write comprehensive type definitions** for better code documentation
7. **Use advanced type features** like conditional and template literal types
8. **Implement type-safe testing utilities** for reliable test suites
Remember that TypeScript is a tool to help you write better JavaScript. The goal is not to use every advanced feature, but to use the right features that solve real problems in your codebase.
---
*Ready to level up your TypeScript skills? Explore our advanced guide on building type-safe GraphQL APIs with TypeScript.*