# Latest Articles
URL: /blog
Blog about web development, design, and other topics.
***
title: Latest Articles
description: Blog about web development, design, and other topics.
date: 2025-06-16T00:00:00.000Z
author:
name: Mew
url: [https://mewis.me](https://mewis.me)
-----------------------------------------
import { ArticlesList } from '@/components/articles/articles-list';
# When to use nullish and or operators in JavaScript
URL: /blog/code-tips/when-to-use-nullish-and-or-operators-in-javascript
A guide to understanding the difference between nullish coalescing and logical OR operators in JavaScript.
***
title: When to use nullish and or operators in JavaScript
description: A guide to understanding the difference between nullish coalescing and logical OR operators in JavaScript.
date: 2025-06-20
parent: "code-tips"
tags: \["javascript", "code-tips"]
----------------------------------
## Introduction
In JavaScript, handling missing or falsy values is a common task, especially when working with dynamic data or user inputs. Two operators often used for this purpose are the `??` (nullish coalescing) and `||` (logical OR) operators. While they may appear similar at first glance, they serve slightly different purposes and behave differently in specific scenarios. This article will explain how each operator works and when you should use one over the other.
### Default Value with `??` and `||`
The `??` (nullish coalescing) and `||` (logical OR) operators in JavaScript are used to provide a default value when the expression on the left-hand side is not provided. They are helpful when handling cases where a value might not exist or is falsy, and you want to ensure a fallback is provided.
### `??` (Nullish Coalescing) Operator
#### What does the `??` operator mean?
The `??` operator is used to provide a **default value** when the expression on the left-hand side is either `null` or `undefined`, but allows other falsy values like `0`, `false`, or `''` (empty string) to remain.
> ✅ This means even if the value is `0`, `false`, or `''`, it will still be used instead of falling back.
### `||` (Logical OR) Operator
#### What does the `||` operator mean?
The `||` operator is quite similar to `??`, but it checks for **all falsy values**, not just `null` or `undefined`. This means it will fall back even if the value is `0`, `false`, or an empty string.
## When to Use `??` vs `||`
Use `??` when working with APIs, optional parameters, or dynamic data that may not always be defined. This way, you provide a fallback without affecting valid falsy values like `false` or an empty string.
Use `||` when you want to treat all falsy values as missing and replace them with a fallback.
## Conclusion
Understanding the difference between `??` and `||` is essential for writing reliable and predictable JavaScript code. Use `??` when you only want to check for `null` or `undefined` and allow other falsy values like `0`, `false`, or `''` to pass through. Use `||` when you want to provide a fallback for **any** falsy value. By choosing the right operator for the context, you can avoid unintended bugs and ensure your application behaves as expected.
# Optimize Tailwind with ESLint & Prettier
URL: /blog/css/boost-your-tailwind-workflow-with-eslint-and-prettier
Streamline your Tailwind CSS workflow by integrating ESLint and Prettier to auto-sort class names and enforce best practices
***
title: "Optimize Tailwind with ESLint & Prettier"
description: "Streamline your Tailwind CSS workflow by integrating ESLint and Prettier to auto-sort class names and enforce best practices"
date: 2025-06-19
parent: tailwindcss
tags: \['tailwindcss', 'eslint', 'prettier']
--------------------------------------------
## Introduction
[Tailwind CSS](https://tailwindcss.com/) is an essential tool for building modern UIs, but let's be real, managing its class names can get messy fast. Ever found yourself staring at an HTML tag loaded with an endless string of utility classes? Or maybe you've caught yourself wondering, “Did I already add ‘px-4' here?” Keeping class names consistent and ordered isn't just about aesthetics; it's about maintaining sanity in collaborative projects.
If you've ever struggled with disorganized Tailwind classes, you're in the right place. In this post, I'll walk you through how to make your Tailwind CSS setup strict and efficient. Using the [Prettier Tailwind CSS plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss), you'll learn how to sort class names following the official Tailwind team's recommendations. Additionally, we'll explore the [ESLint Tailwind CSS plugin](https://www.npmjs.com/package/eslint-plugin-tailwindcss), which not only enforces class order but offers even more capabilities to improve your workflow. By the end, you'll have a clean, consistent codebase that's easier to read, debug, and scale.
Let's dive in and clean up that class name chaos.
### Tutorial: Setting Up a Strict Tailwind CSS Workflow
#### Step 1: Install Required Dependencies
To get started, you'll need to install some packages that will make this setup possible. Run the following command to add them to your project:
> **I will be using** [bun](https://bun.sh) as my package manager, but feel free to use whatever works for you.
In addition to core ESLint and Prettier packages themselves, this installs both the [Prettier Tailwind CSS plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss) for sorting class names and the [ESLint Tailwind CSS plugin](https://www.npmjs.com/package/eslint-plugin-tailwindcss) for validating and enforcing best practices.
#### Step 2: Configure Prettier
Next, let's set up Prettier to automatically sort Tailwind CSS class names. Open your `.prettierrc` (or [equivalent](https://prettier.io/docs/en/configuration.html)) file (or create one if it doesn't exist) and add the following configuration:
Prettier will now automatically sort Tailwind CSS class names every time you format your code.
#### Step 3: Configure ESLint
##### ESLint 8
The steps below are for ESLint 8, which is soon to be deprecated, so you might consider upgrading your version. Check our this [migration guide](https://eslint.org/docs/latest/use/configure/migration-guide) for that.
Now, let's configure ESLint to enhance your Tailwind CSS setup. Open your `.eslintrc.json` file and update it with these settings:
##### shadcn/ui cn function
If you're using utility functions like cn from [shadcn/ui](https://ui.shadcn.com/) [or cva fr](https://ui.shadcn.com/)om the [`class-variance-authority`](https://cva.style/docs) [package, you'll need to](https://cva.style/docs) update your ESLint configuration to recognize these functions. Add the following to your `.eslintrc.json` file:
This is particularly useful when you dynamically generate class names, ensuring even complex class strings follow Tailwind's rules.
##### ESLint 9
In ESLint 9, they moved to use a new flat config format (typically configured in an `eslint.config.js` file), and they provide a very helpful [configuration migrator](https://www.npmjs.com/package/@eslint/migrate-config) that we can run on our existing config file to convert it to the new format. To use it do the following to your existing configuration file (`.eslintrc`, `.eslintrc.json`, `.eslintrc.yml`):
This will create a starting point for your `eslint.config.js` file but is not guaranteed to work immediately without further modification.
If you want to do it manually, you can create a new `eslint.config.js` file and paste the following to it.
#### Step 4: Verify the setup
With everything configured, it's time to test the setup. Create a file with some unordered Tailwind CSS classes, like this:
`} title="index.tsx" lang="xml" />
Run Prettier to format the file, and ESLint to validate it. After formatting, the class names will be ordered automatically:
`} title="index.tsx" lang="xml" />
#### Step 5: Add to Your Workflow
To make the most of this setup, integrate these tools into your workflow:
* Use Prettier with your code editor (e.g., enable auto-formatting in VS Code).
* Add ESLint to your CI/CD pipeline or Git hooks using a tool like Husky to enforce rules before committing code.
## Conclusion
Keeping class names organized and consistent is crucial for maintaining a clean and readable codebase. With a little effort upfront, you can simplify your workflow, avoid common pitfalls, and create a more collaborative coding environment. Consistency makes all the difference.
Thanks for reading this far.
# How caching works in Next.js
URL: /blog/nextjs/how-caching-works-in-nextjs
Learn how caching works in Next.js and how to optimize your app's performance.
***
title: How caching works in Next.js
description: Learn how caching works in Next.js and how to optimize your app's performance.
date: 2025-06-16
parent: nextjs
tags: \['nextjs', 'caching']
author:
name: Mew
url: [https://mewis.me](https://mewis.me)
-----------------------------------------
## Introduction
Caching is a powerful technique that significantly enhances the performance and efficiency of web applications. Next.js, a popular React framework, leverages multiple caching strategies to reduce unnecessary data fetching, speed up page loads, and optimize the user experience. By strategically storing data and page content, Next.js minimizes server load and maximizes responsiveness.
### The Four Caching Systems
#### 1. Request Memoization
This is the most basic form of caching. When your code makes the same data request multiple times during a single page render, Next.js only executes that request once.
**For example, if three components on your page need the same data, the actual fetch happens once, and the result is shared.** This happens automatically when you use the fetch API in your components. The cache only lasts for the current request → once the page is sent to the user, this cache is cleared.
#### 2. Data Cache
The Data Cache stores the results of fetch requests on the server across multiple user requests and even across deployments.
When you fetch data in a component, Next.js checks if that data is already in the Data Cache. If it is, it uses the cached data instead of making a new request to your data source. This makes your application faster and reduces load on your databases or APIs.
By default, **data is cached indefinitely**, but you can control this by setting revalidation rules (or [**opting out for a page**](https://nextjs.org/docs/app/building-your-application/caching#opting-out-2)):
You can also trigger revalidation manually using `revalidatePath` or `revalidateTag` functions.
#### 3. Full Route Cache
Next.js doesn't just cache data. It can cache entire rendered pages. When a route is statically rendered, Next.js saves:
* The HTML of the page
* The React Server Component Payload (a compact representation of your server components)
This means Next.js doesn't have to re-render these pages for each visitor. Instead, it serves the pre-generated content, making page loads very fast.
Routes are statically rendered by default unless you use dynamic features like cookies, headers, or uncached data fetches.
#### 4. Router Cache
This cache exists in the user's browser memory during a session. When a user navigates between pages, Next.js stores the previously visited routes. This enables instant back/forward navigation without making new requests to the server.
This cache is temporary and only lasts during the user's session. It's cleared when the page is refreshed.
### How These Caches Work Together
These caching systems don't work alone → they create a complete caching strategy:
When building your app, Next.js statically renders pages and stores them in the Full Route Cache.
1. When fetching data, the Data Cache stores results to avoid repeated data fetches.
2. During a single page render, Request Memoization ensures each unique data request only happens once.
3. As users navigate your site, the Router Cache enables fast navigation between pages they've already visited.
### Controlling Cache Behavior
You can control caching in several ways:
* For data caching, use the `cache` and `next.revalidate` options with `fetch`.
* For route caching, use dynamic functions like `cookies()` or `headers()` to make routes dynamic.
* For time-based revalidation, use the `revalidate` option.
* For on-demand revalidation, use `revalidatePath` or `revalidateTag` in Server Actions.
When you want fresh data, you have options:
* Revalidate on a time interval
* Revalidate on specific events
* Opt out of caching entirely
## Conclusion
**Request Memoization**: Saves the results of fetch calls during a single page render. It prevents duplicate data fetches within the same component tree. This cache lasts only for the current request and is cleared once rendering completes. It happens automatically with no configuration needed.
**Data Cache**: Persists fetch results on the server across multiple user requests and deployments. This allows Next.js to reuse previously fetched data without hitting your data sources repeatedly. This cache is persistent until manually revalidated. Control it using fetch options like `cache: 'no-store'` to disable caching or `next: { revalidate: seconds }` to set time-based revalidation.
**Full Route Cache**: Stores pre-rendered HTML and React Server Component Payloads for entire routes. This cache eliminates the need to re-render pages for each visitor. It persists across requests and is invalidated on redeployment or when the Data Cache is revalidated. Routes become dynamic (not cached) when using dynamic functions like cookies, headers, or uncached data fetches.
**Router Cache**: Stores previously visited routes in the user's browser memory. This enables instant navigation between pages without additional server requests. This cache lasts for the user's session and is cleared on page refresh. Navigation with the `` component uses this cache automatically.
Thank you for reading!
# Top 5 Next.js alternatives for React developers
URL: /blog/nextjs/top-5-nextjs-alternatives-for-react-developers
Discover the top alternatives to Next.js for React developers seeking flexibility and enhanced performance in web app development.
***
title: Top 5 Next.js alternatives for React developers
description: Discover the top alternatives to Next.js for React developers seeking flexibility and enhanced performance in web app development.
date: 2025-06-16
parent: nextjs
tags: \['nextjs', 'alternatives']
author:
name: Mew
url: [https://mewis.me](https://mewis.me)
-----------------------------------------
## Introduction
Next.js has earned its place as one of the most popular frameworks in the React ecosystem. It gives you just about everything you need to build a modern web app with React—file-based routing, server-side rendering, static generation, and many other full-stack features.
Over time, Next.js has also become much more complex. Features like the App Router, Server Components, middleware, and streaming APIs have made it powerful but also more opinionated and less predictable. Additionally, Next.js (and Vercel, its parent company) has faced criticism lately, especially around vendor lock-in and the pace of change, leaving developers behind.
If you're looking for a Next.js alternative and want to keep using React, you're not short on options. In this article, we'll cover the best frameworks to consider, what they offer, where they shine, and when they might be a better fit than Next.js.
### Next.js alternatives overview
Before we proceed with the article, here's a high-level overview of the alternatives we'll be reviewing:
| **Framework** | **Best For** | **React Support** | **SSR Support** | **Routing** | **Data Loading** | **Type Safety** |
| ----------------------- | ------------------------------------------------------ | ----------------- | --------------------- | ---------------------------------- | ---------------------------------------- | -------------------- |
| **Remix** | **Full-stack apps with built-in form/data primitives** | **Full** | **Yes** | **File-based + loaders/actions** | **Loaders + actions (built-in)** | **Yes** |
| **Astro** | **Content-heavy static or hybrid sites** | **Partial** | **Yes (newer)** | **File-based with islands** | **JS fetch in Astro components** | **Yes** |
| **TanStack Start** | **Fully type-safe full-stack React apps** | **Full** | **Yes** | **File-based via TanStack Router** | **Server functions + typed loaders** | **Yes (full stack)** |
| **Vike** | **Full control over SSR/SSG with minimal abstraction** | **Full** | **Yes** | **Convention-based (+Page.tsx)** | **Custom server Hooks (onBeforeRender)** | **Yes** |
| **Vite + React Router** | **Lightweight client-side React apps** | **Full** | **No (manual setup)** | **Manual via React Router** | **React Router loaders** | **Yes** |
### Remix
[Remix](https://remix.run/) is one of the strongest alternatives to Next.js, especially if you still want to stick with React but don't like the direction Next.js is going.
Remix respects how the web works. It doesn't try to abstract everything into framework magic; instead, it builds on native browser features like forms, caching, and HTTP requests and gives you a modern, React-first experience on top of that. It's also completely platform-agnostic.
Let's explore some of its core features and drawbacks below.
#### Features
* **File-based routing –** Like Next.js, Remix uses a file-based routing system. However, instead of just mapping files to pages, each route can define its `loader()` for data fetching and `action()` for mutations like form submissions. These functions run server-side and are tightly scoped to the route itself, with no extra API layer required.
* **Built-in SSR –** SSR is the default in Remix, but it's not forced. Data is fetched server-side via loaders, injected directly into components, and hydrated client-side without requiring suspense, RSC, or client fetch hacks.
* **Smart caching strategy –** Remix uses standard HTTP caching headers. You control caching behavior using Cache-Control, ETags, etc.
#### Drawbacks
* **Smaller ecosystem –** Compared to Next.js, Remix has fewer plugins, integrations, and tutorials. You'll find yourself building more from scratch or reading source code
* **Opinionated about the web –** Remix does a lot of things the web way, and while this is powerful, it's not for everyone. If you prefer high-level abstractions over explicit control, it might feel like more work
#### Developer experience
Similar to Next.js, Remix uses a file-based routing system but with a more focused design. Each route is fully self-contained and handles its data fetching with a `loader()` function and mutations with an `action()`. There's no need to fetch data at the top level or pass props down manually.
For example, here's what a simple blog route looks like in Remix:
{
const res = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=5");
if (!res.ok) throw new Response("Failed to fetch posts", { status: res.status });
const posts = await res.json();
return json({ posts });
};
export default function Blog() {
const { posts } = useLoaderData();
return (
Latest Posts
{posts.map((post) => (
{post.title}
{post.body}
))}
);
}`}
lang="tsx"
title={`blog.tsx`}
/>
This example blog page fetches data on the server using the `loader()` and renders the posts without any client-side fetching or prop drilling.
Remix also lets you use standard React patterns if you do want client-side interactivity:
{
setLoading(true);
const res = await fetch(\`https://jsonplaceholder.typicode.com/posts?q=\${query}\`);
const data = await res.json();
setResults(data);
setLoading(false);
};
return (
Search Posts
setQuery(e.target.value)} />
{results.map((post) => (
{post.title}
))}
);
}`}
lang="tsx"
title={`search.tsx`}
/>
Remix doesn't get in the way of standard React. It just makes server-side logic simpler and more structured when you need it.
### Astro
[Astro](https://astro.build/) isn't explicitly a React framework. However, it integrates well with React, and depending on what you're building, it might be a better fit than Next.js. Astro is built for content-heavy sites such as blogs, landing pages, documentation, etc., where performance matters more than full client-side interactivity. Its core strength is the island architecture, which renders everything as static HTML by default, and only the interactive parts of the page are hydrated with JavaScript. This way, you get tiny JS bundles and fast page loads.
#### Features
* **Partial hydration –** Instead of booting up a full React app on the client, Astro sends down plain HTML and hydrates components only where needed using its islands architecture
* **Framework agnostic –** You can use React, Vue, Svelte, Solid, or Preact, even in the same project
* **Built-in markdown/MDX support –** First-class content authoring experience. Embed components directly in your .mdx files without extra tooling
* **Hybrid rendering –** While Astro started as a static site generator, it now supports SSR and hybrid rendering. You can statically generate most pages and use SSR only where you need it
#### Drawbacks
* **Not a full React app –** Astro is great for static and semi-dynamic sites, but if you're building a highly interactive SPA or complex dashboard, it might feel limiting
* **Less mature SSR –** SSR support exists and works, but it's still newer and not as widely battle-tested as Next.js or Remix in complex, dynamic environments
#### Developer experience
As mentioned earlier, Astro pages are mostly HTML-first. You can drop in React (or any framework) components wherever interactivity is needed. Here's a basic example of a blog page:
Blog