584 lines
13 KiB
TypeScript
584 lines
13 KiB
TypeScript
"use client"
|
|
|
|
import fs from "fs"
|
|
import path from "path"
|
|
import matter from "gray-matter"
|
|
|
|
const postsDirectory = path.join(process.cwd(), "posts")
|
|
|
|
export interface PostMetadata {
|
|
title: string
|
|
date: string
|
|
excerpt: string
|
|
[key: string]: any
|
|
}
|
|
|
|
export interface Post {
|
|
slug: string
|
|
content: string
|
|
metadata: PostMetadata
|
|
}
|
|
|
|
// Create posts directory if it doesn't exist
|
|
try {
|
|
if (!fs.existsSync(postsDirectory)) {
|
|
fs.mkdirSync(postsDirectory, { recursive: true })
|
|
createSamplePosts()
|
|
}
|
|
} catch (error) {
|
|
console.error("Error checking or creating posts directory:", error)
|
|
}
|
|
|
|
// Changed to synchronous to avoid suspense issues
|
|
export function getAllPosts(): Post[] {
|
|
try {
|
|
const filenames = fs.readdirSync(postsDirectory)
|
|
|
|
const posts = filenames
|
|
.filter((filename) => filename.endsWith(".md"))
|
|
.map((filename) => {
|
|
const slug = filename.replace(/\.md$/, "")
|
|
const fullPath = path.join(postsDirectory, filename)
|
|
const fileContents = fs.readFileSync(fullPath, "utf8")
|
|
const { data, content } = matter(fileContents)
|
|
|
|
return {
|
|
slug,
|
|
content,
|
|
metadata: data as PostMetadata,
|
|
}
|
|
})
|
|
|
|
return posts
|
|
} catch (error) {
|
|
console.error("Error getting all posts:", error)
|
|
return []
|
|
}
|
|
}
|
|
|
|
// Changed to synchronous to avoid suspense issues
|
|
export function getPostBySlug(slug: string): Post | null {
|
|
try {
|
|
const fullPath = path.join(postsDirectory, `${slug}.md`)
|
|
const fileContents = fs.readFileSync(fullPath, "utf8")
|
|
const { data, content } = matter(fileContents)
|
|
|
|
return {
|
|
slug,
|
|
content,
|
|
metadata: data as PostMetadata,
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error getting post by slug ${slug}:`, error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
function createSamplePosts() {
|
|
const samplePosts = [
|
|
{
|
|
filename: "getting-started-with-nextjs.md",
|
|
content: `---
|
|
title: "Getting Started with Next.js"
|
|
date: "2023-05-15"
|
|
excerpt: "Learn how to build modern web applications with Next.js"
|
|
---
|
|
|
|
# Getting Started with Next.js
|
|
|
|
Next.js is a React framework that enables functionality such as server-side rendering and static site generation.
|
|
|
|
## Why Next.js?
|
|
|
|
- **Server-side Rendering**: Improves performance and SEO
|
|
- **Static Site Generation**: Pre-renders pages at build time
|
|
- **API Routes**: Build API endpoints as part of your Next.js app
|
|
- **File-based Routing**: Create routes based on your file structure
|
|
|
|
## Getting Started
|
|
|
|
To create a new Next.js app, run:
|
|
|
|
\`\`\`bash
|
|
npx create-next-app@latest my-app
|
|
\`\`\`
|
|
|
|
This will set up everything automatically for you.`,
|
|
},
|
|
{
|
|
filename: "markdown-styling-guide.md",
|
|
content: `---
|
|
title: "Markdown Styling Guide"
|
|
date: "2023-06-22"
|
|
excerpt: "Learn how to style your markdown content for better readability"
|
|
---
|
|
|
|
# Markdown Styling Guide
|
|
|
|
Markdown is a lightweight markup language that you can use to add formatting elements to plaintext text documents.
|
|
|
|
## Basic Syntax
|
|
|
|
### Headers
|
|
|
|
# H1
|
|
## H2
|
|
### H3
|
|
|
|
### Emphasis
|
|
|
|
*This text will be italic*
|
|
_This will also be italic_
|
|
|
|
**This text will be bold**
|
|
__This will also be bold__
|
|
|
|
### Lists
|
|
|
|
Unordered:
|
|
|
|
- Item 1
|
|
- Item 2
|
|
- Item 2a
|
|
- Item 2b
|
|
|
|
Ordered:
|
|
|
|
1. Item 1
|
|
2. Item 2
|
|
3. Item 3
|
|
|
|
### Links
|
|
|
|
[GitHub](http://github.com)
|
|
|
|
### Images
|
|
|
|

|
|
|
|
### Code
|
|
|
|
Inline \`code\` has \`back-ticks around\` it.
|
|
|
|
\`\`\`javascript
|
|
var s = "JavaScript syntax highlighting";
|
|
alert(s);
|
|
\`\`\``,
|
|
},
|
|
{
|
|
filename: "building-accessible-websites.md",
|
|
content: `---
|
|
title: "Building Accessible Websites"
|
|
date: "2023-07-10"
|
|
excerpt: "Learn how to make your websites accessible to everyone"
|
|
---
|
|
|
|
# Building Accessible Websites
|
|
|
|
Web accessibility means that websites, tools, and technologies are designed and developed so that people with disabilities can use them.
|
|
|
|
## Why Accessibility Matters
|
|
|
|
- **Inclusivity**: Everyone should be able to access and use web content
|
|
- **Legal Requirements**: Many countries have laws requiring web accessibility
|
|
- **Better UX**: Accessible sites often provide better user experience for everyone
|
|
- **SEO Benefits**: Many accessibility practices improve SEO
|
|
|
|
## Key Accessibility Practices
|
|
|
|
### Semantic HTML
|
|
|
|
Use the right HTML elements for their intended purpose:
|
|
|
|
\`\`\`html
|
|
<!-- Bad -->
|
|
<div class="button" onclick="submit()">Submit</div>
|
|
|
|
<!-- Good -->
|
|
<button onclick="submit()">Submit</button>
|
|
\`\`\`
|
|
|
|
### Keyboard Navigation
|
|
|
|
Ensure all interactive elements are keyboard accessible:
|
|
|
|
- Use proper focus states
|
|
- Maintain a logical tab order
|
|
- Provide skip links
|
|
|
|
### Alternative Text
|
|
|
|
Always provide alt text for images:
|
|
|
|
\`\`\`html
|
|
<img src="chart.png" alt="Bar chart showing sales data for Q1 2023">
|
|
\`\`\``,
|
|
},
|
|
// Adding 5 more dummy posts
|
|
{
|
|
filename: "modern-css-techniques.md",
|
|
content: `---
|
|
title: "Modern CSS Techniques for 2023"
|
|
date: "2023-08-05"
|
|
excerpt: "Explore the latest CSS features and techniques that are changing web development"
|
|
---
|
|
|
|
# Modern CSS Techniques for 2023
|
|
|
|
CSS has evolved significantly in recent years, with powerful new features that make complex layouts and effects easier than ever.
|
|
|
|
## CSS Grid
|
|
|
|
CSS Grid has revolutionized web layouts:
|
|
|
|
\`\`\`css
|
|
.container {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
\`\`\`
|
|
|
|
## CSS Custom Properties (Variables)
|
|
|
|
Variables make your CSS more maintainable:
|
|
|
|
\`\`\`css
|
|
:root {
|
|
--primary-color: #3490dc;
|
|
--secondary-color: #ffed4a;
|
|
}
|
|
|
|
.button {
|
|
background-color: var(--primary-color);
|
|
}
|
|
\`\`\`
|
|
|
|
## Container Queries
|
|
|
|
Container queries allow you to style elements based on their parent container's size:
|
|
|
|
\`\`\`css
|
|
@container (min-width: 700px) {
|
|
.card {
|
|
display: grid;
|
|
grid-template-columns: 2fr 1fr;
|
|
}
|
|
}
|
|
\`\`\`
|
|
|
|
## Logical Properties
|
|
|
|
Logical properties make internationalization easier:
|
|
|
|
\`\`\`css
|
|
.element {
|
|
margin-inline: 1rem;
|
|
padding-block: 0.5rem;
|
|
}
|
|
\`\`\`
|
|
|
|
## Conclusion
|
|
|
|
Modern CSS is more powerful than ever, enabling developers to create complex layouts and effects with less code and greater flexibility.`,
|
|
},
|
|
{
|
|
filename: "typescript-best-practices.md",
|
|
content: `---
|
|
title: "TypeScript Best Practices for Large Projects"
|
|
date: "2023-08-12"
|
|
excerpt: "Learn how to effectively use TypeScript in large-scale applications"
|
|
---
|
|
|
|
# TypeScript Best Practices for Large Projects
|
|
|
|
TypeScript has become the standard for large-scale JavaScript applications. Here are some best practices to keep your codebase maintainable.
|
|
|
|
## Type Everything
|
|
|
|
Always define types for your data structures:
|
|
|
|
\`\`\`typescript
|
|
interface User {
|
|
id: string;
|
|
name: string;
|
|
email: string;
|
|
role: 'admin' | 'user' | 'guest';
|
|
preferences?: UserPreferences;
|
|
}
|
|
|
|
// Instead of:
|
|
// const user = { id: '123', name: 'John' };
|
|
\`\`\`
|
|
|
|
## Use Discriminated Unions
|
|
|
|
Discriminated unions make your code more type-safe:
|
|
|
|
\`\`\`typescript
|
|
type Success = {
|
|
status: 'success';
|
|
data: User[];
|
|
};
|
|
|
|
type Error = {
|
|
status: 'error';
|
|
message: string;
|
|
};
|
|
|
|
type ApiResponse = Success | Error;
|
|
|
|
function handleResponse(response: ApiResponse) {
|
|
if (response.status === 'success') {
|
|
// TypeScript knows response.data exists
|
|
return response.data;
|
|
} else {
|
|
// TypeScript knows response.message exists
|
|
throw new Error(response.message);
|
|
}
|
|
}
|
|
\`\`\`
|
|
|
|
## Avoid Any
|
|
|
|
The \`any\` type defeats the purpose of TypeScript. Use \`unknown\` instead when necessary:
|
|
|
|
\`\`\`typescript
|
|
// Bad
|
|
function parseData(data: any) {
|
|
return data.items;
|
|
}
|
|
|
|
// Good
|
|
function parseData(data: unknown) {
|
|
if (typeof data === 'object' && data !== null && 'items' in data) {
|
|
return (data as { items: unknown[] }).items;
|
|
}
|
|
throw new Error('Invalid data format');
|
|
}
|
|
\`\`\`
|
|
|
|
## Conclusion
|
|
|
|
Following these best practices will help you build more maintainable and robust TypeScript applications.`,
|
|
},
|
|
{
|
|
filename: "serverless-architecture.md",
|
|
content: `---
|
|
title: "Introduction to Serverless Architecture"
|
|
date: "2023-08-20"
|
|
excerpt: "Understand the benefits and challenges of serverless computing"
|
|
---
|
|
|
|
# Introduction to Serverless Architecture
|
|
|
|
Serverless computing allows developers to build and run applications without thinking about servers.
|
|
|
|
## What is Serverless?
|
|
|
|
Despite the name, serverless doesn't mean there are no servers. It means you don't have to manage them:
|
|
|
|
- No provisioning servers
|
|
- No worrying about scaling
|
|
- Pay only for what you use
|
|
- Focus on code, not infrastructure
|
|
|
|
## Key Serverless Services
|
|
|
|
### AWS Lambda
|
|
|
|
\`\`\`javascript
|
|
exports.handler = async (event) => {
|
|
const result = await processData(event.data);
|
|
return {
|
|
statusCode: 200,
|
|
body: JSON.stringify(result)
|
|
};
|
|
};
|
|
\`\`\`
|
|
|
|
### Azure Functions
|
|
|
|
\`\`\`javascript
|
|
module.exports = async function (context, req) {
|
|
const result = await processData(req.body);
|
|
context.res = {
|
|
status: 200,
|
|
body: result
|
|
};
|
|
};
|
|
\`\`\`
|
|
|
|
## Challenges
|
|
|
|
Serverless isn't perfect for every use case:
|
|
|
|
- Cold starts can impact performance
|
|
- Long-running processes aren't ideal
|
|
- Debugging can be more difficult
|
|
- Vendor lock-in concerns
|
|
|
|
## Conclusion
|
|
|
|
Serverless architecture can significantly reduce operational complexity and cost for many applications, but it's important to understand its limitations and use cases.`,
|
|
},
|
|
{
|
|
filename: "react-performance-optimization.md",
|
|
content: `---
|
|
title: "React Performance Optimization Techniques"
|
|
date: "2023-08-25"
|
|
excerpt: "Learn how to make your React applications faster and more efficient"
|
|
---
|
|
|
|
# React Performance Optimization Techniques
|
|
|
|
Performance optimization is crucial for providing a good user experience in React applications.
|
|
|
|
## Use React.memo for Component Memoization
|
|
|
|
Prevent unnecessary re-renders with React.memo:
|
|
|
|
\`\`\`jsx
|
|
const ExpensiveComponent = React.memo(({ data }) => {
|
|
// Render using data
|
|
return <div>{/* ... */}</div>;
|
|
});
|
|
\`\`\`
|
|
|
|
## Virtualize Long Lists
|
|
|
|
Use virtualization for long lists:
|
|
|
|
\`\`\`jsx
|
|
import { FixedSizeList } from 'react-window';
|
|
|
|
function VirtualizedList({ items }) {
|
|
const Row = ({ index, style }) => (
|
|
<div style={style}>
|
|
{items[index].name}
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<FixedSizeList
|
|
height={500}
|
|
width={300}
|
|
itemCount={items.length}
|
|
itemSize={35}
|
|
>
|
|
{Row}
|
|
</FixedSizeList>
|
|
);
|
|
}
|
|
\`\`\`
|
|
|
|
## Code Splitting
|
|
|
|
Split your code to load only what's needed:
|
|
|
|
\`\`\`jsx
|
|
import React, { Suspense, lazy } from 'react';
|
|
|
|
const HeavyComponent = lazy(() => import('./HeavyComponent'));
|
|
|
|
function App() {
|
|
return (
|
|
<Suspense fallback={<div>Loading...</div>}>
|
|
<HeavyComponent />
|
|
</Suspense>
|
|
);
|
|
}
|
|
\`\`\`
|
|
|
|
## Avoid Inline Functions in Renders
|
|
|
|
Inline functions cause unnecessary re-renders:
|
|
|
|
\`\`\`jsx
|
|
// Bad
|
|
return <button onClick={() => handleClick(id)}>Click me</button>;
|
|
|
|
// Good
|
|
const handleButtonClick = useCallback(() => {
|
|
handleClick(id);
|
|
}, [id, handleClick]);
|
|
|
|
return <button onClick={handleButtonClick}>Click me</button>;
|
|
\`\`\`
|
|
|
|
## Conclusion
|
|
|
|
By implementing these optimization techniques, you can significantly improve the performance of your React applications.`,
|
|
},
|
|
{
|
|
filename: "docker-for-developers.md",
|
|
content: `---
|
|
title: "Docker for Frontend Developers"
|
|
date: "2023-09-01"
|
|
excerpt: "A practical guide to using Docker in frontend development workflows"
|
|
---
|
|
|
|
# Docker for Frontend Developers
|
|
|
|
Docker can streamline your frontend development workflow and ensure consistency across environments.
|
|
|
|
## Why Use Docker for Frontend?
|
|
|
|
- **Consistency**: Same environment for all developers
|
|
- **Isolation**: Dependencies don't conflict with your system
|
|
- **CI/CD Integration**: Easier testing and deployment
|
|
- **Microservices**: Better for modern architecture
|
|
|
|
## Basic Dockerfile for a React App
|
|
|
|
\`\`\`dockerfile
|
|
# Build stage
|
|
FROM node:16-alpine as build
|
|
WORKDIR /app
|
|
COPY package*.json ./
|
|
RUN npm install
|
|
COPY . .
|
|
RUN npm run build
|
|
|
|
# Production stage
|
|
FROM nginx:alpine
|
|
COPY --from=build /app/build /usr/share/nginx/html
|
|
EXPOSE 80
|
|
CMD ["nginx", "-g", "daemon off;"]
|
|
\`\`\`
|
|
|
|
## Docker Compose for Development
|
|
|
|
\`\`\`yaml
|
|
version: '3'
|
|
services:
|
|
frontend:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile.dev
|
|
volumes:
|
|
- ./src:/app/src
|
|
ports:
|
|
- "3000:3000"
|
|
environment:
|
|
- NODE_ENV=development
|
|
\`\`\`
|
|
|
|
## Tips for Frontend Docker Setups
|
|
|
|
1. Use multi-stage builds to keep images small
|
|
2. Mount volumes for hot reloading in development
|
|
3. Consider using Docker for your API during development
|
|
4. Use environment variables for configuration
|
|
|
|
## Conclusion
|
|
|
|
Docker can significantly improve your frontend development workflow, especially for complex applications or teams with multiple developers.`,
|
|
},
|
|
]
|
|
|
|
samplePosts.forEach((post) => {
|
|
fs.writeFileSync(path.join(postsDirectory, post.filename), post.content)
|
|
})
|
|
}
|