Why this Project ?
I've been thinking about creating a blog writing platform for quite a while now. The idea of building something I actually use is really exciting to me. It's a space where I can share my thoughts, document my learning journey, and showcase my projects.
I might not be able to include all those features or create a perfectly reliable, scalable, and smooth blog writing platform, but I'm going to use the skills I have to make it as smooth as possible—and I'm going to enjoy every moment of it!
My Approach to the project
Planning and Ideation:
Well the main idea behind or my main strong force that drives me to build this project was first, i was looking to create a platform for blog writing and other is Roadmap.sh platform. Here i got the idea of how different section is gonna be in a pretty easy and clear way. They have mentioned everythign that’s required for a minimal blog website.
Choosing the Tech Stacks:
Since I’m Passionate about the MERN stack, I decided to use it for this project:
MongoDB: for managing the blog posts and user data
Express.js and Node.js : for backend APIs
React: for building the user interface
Tailwind CSS: to style the blog
Quill: Rick text editor (NPM library)
Different concepts and revisions of concepts that I worked on while building this project.
Understanding the proxy:
I've been using proxies quite a bit when building projects with the MERN stack. At first, I thought it was just a way to shorten URLs, like changing
http://localhost:5000
to something simpler like "/api" and then adding extra endpoints. But I was mistaken. The real purpose of using a proxy invite.config.js
is to bypass CORS (Cross-Origin Resource Sharing). I was even using CORS in the backend along with the proxy.export default { server: { proxy: { "/api": { target: "http://localhost:5000", changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ""), }, }, }, };
Why do we use a proxy?: A proxy helps reroute requests from the frontend to the backend, mimicking same-origin requests and preventing CORS errors during development.
Base URL Configuration in axios:
Axios is a popular JavaScript library used to perform HTTP requests from the browser to the server. I appreciated how it allowed me to use my API in different places and modules by setting a base URL. This way, I adhered to the DRY (Don't Repeat Yourself) principle, making my code cleaner and more efficient.
import { clsx } from "clsx"; import { twMerge } from "tailwind-merge" import axios from "axios"; export function cn(...inputs) { return twMerge(clsx(inputs)); } // creating the baseURL in axios export const api = axios.create({ baseURL:import.meta.env.VITE_API_BASE_URL })
This simple and small code make the code cleaner and more readable.
Quill Editor
This is my first time using the Quill editor, and it was very easy to use. I found plenty of help from the community and Stack Overflow. It's a rich text editor that lets us perform various text-based operations.
.This text editor store the text in the delta format, where you will be having the text with differente attributes.
Rendering the Quill text from the database:
Once you've saved your text or created a blog, the next step is to make sure it shows up just like you wrote it. To do this, we'll use another library called quill-delta-to-html. This lets us turn the delta format text into regular HTML, since the DOM understands HTML, not delta formats. Plus, we'll need to use quill/dist/quill.snow.css. Since I'm using Tailwind, I can even customize the text editor and how it's displayed in the DOM. This gives me all the power to make it look prettier and really awesome.
Skeleton Loader for Better UX :
I've visited different web apps and websites, and I always notice something intriguing: the empty loader that appears when data hasn't been fetched from the server yet. Once the data arrives, the DOM updates. That's called a skeleton loader. Isn't it fascinating how it enhances the user experience? I really love it!
<div className="skeleton h-4 w-48 bg-gray-200 rounded"></div>
Middelware in Mongoose Schema:
Middleware acts like a middleman that you go through before reaching your main controller function or performing any logic afterward. In short, it gives you access to both the request and response objects.
With this, we can even use middleware in a Mongoose schema, like performing a slugify operation before saving our document. These are known as pre and post hooks. We can apply middleware to the parent document in Mongoose, but not to the subdocument of the schema. Here are some situations where we use middleware:
Logging: This can be used to log the incoming requests , including details such as the url, methods and headers.
Authentication: Middelware can be used to authenticate users before allowing them to access protected resources.
Error Handeling: Middelware can be used to handle errors too.
Another important concept I learned is that we cannot use the this
keyword in middleware when using arrow functions, so we must use an anonymous function instead.
Rate Limiting in Node.js Server
Rate limiting is a method employed to regulate the number of requests a client can make to a server within a defined time period. This approach helps prevent misuse, safeguards server resources, and improves the overall security of an application by restricting excessive or harmful traffic, such as DDoS attacks.
Adding advanced features to my current project.
Exploring more about server-side optimizations.
Building something new and challenging!
Implementation of protected routes based on JWT authentication:
JWT is a neat and secure way to send info between parties as a JSON object. It's super popular for authentication because it lets users prove who they are without having to send their username and password every time they make a request.
My First Encounter with useReducer
: A Game-Changer in State Management
There are moments in every developer’s journey that leave you awestruck—a moment where you discover something so efficient, so intuitive, that it transforms the way you approach your work. For me, that moment was the first time I used useReducer
in React.
Why I Turned to useReducer
Before useReducer
, I had been managing state using plain useState
, and while it worked for simple cases, things started to spiral out of control when my app became more complex. I found myself juggling multiple state variables, writing repetitive logic, and trying to keep track of how state changes were interconnected. It was messy, and it was frustrating.
Then came useReducer
—the knight in shining armor I didn’t know I needed.
const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
case 'reset':
return { count: 0 };
default:
throw new Error('Unknown action type');
}
};
to know more about usereducer check this article : usereducer
Final Thoughts
This journey isn't just about coding; it's about learning, growing, and sharing. Writing this blog post has given me a chance to think about the skills I've gained and the challenges I've faced. If you're on a similar path, I'd love to hear about your experiences. Let's grow together! 🚀