agent-rules-kit
Version:
CLI tool to bootstrap AI agent rules for multiple IDEs and frameworks. Generates optimized rules for Cursor, VS Code, Claude, and 6+ other AI coding assistants.
358 lines (290 loc) • 9.77 kB
Markdown
---
description: Feature-Sliced Design architecture for React applications
globs: <root>/src/**/*.ts,<root>/src/**/*.tsx,<root>/src/**/*.js,<root>/src/**/*.jsx
alwaysApply: false
---
# Feature Sliced Design Architecture in React
Feature Sliced Design (FSD) is a methodology for organizing code in frontend applications by features and layers, emphasizing isolation, domain-driven structure, and explicit relationships between modules.
## Core Principles
1. **Feature-Based Organization**: Code is organized by features or business domains
2. **Slice-Based Decomposition**: Features are divided into self-contained slices
3. **Layer-Based Segmentation**: Code within slices is organized by layers (UI, logic, etc.)
4. **Public API Boundaries**: Modules expose only what's necessary via public APIs
## Layers Hierarchy
FSD organizes code into layers, with each higher layer able to use modules from lower layers:
1. **app** - Application initialization, global providers, styles
2. **processes** - Complex workflows involving multiple entities/features
3. **pages** - Application route components
4. **widgets** - Complex, composite components for specific business scenarios
5. **features** - User interactions that change business data/logic
6. **entities** - Core business objects with logic and data
7. **shared** - Reusable utilities, UI kit, types, etc.
## Directory Structure
```
src/
├── app/ # Application setup
│ ├── providers/ # Application providers
│ ├── styles/ # Global styles
│ └── index.tsx # Entry point
├── processes/ # Cross-feature processes
│ ├── authentication/ # Auth process
│ └── payment/ # Payment process
├── pages/ # Routes/pages
│ ├── home/
│ ├── profile/
│ └── dashboard/
├── widgets/ # Composite blocks
│ ├── header/
│ ├── sidebar/
│ └── product-card/
├── features/ # User interactions
│ ├── auth/
│ │ ├── login/
│ │ ├── logout/
│ │ └── register/
│ ├── cart/
│ │ ├── add-to-cart/
│ │ └── remove-from-cart/
│ └── product/
│ ├── filter-products/
│ └── sort-products/
├── entities/ # Business entities
│ ├── user/
│ ├── product/
│ └── order/
└── shared/ # Shared utilities
├── api/ # API clients
├── config/ # Configuration
├── lib/ # External libraries
└── ui/ # UI kit
```
## Segment Structure
Each segment (feature, entity, etc.) follows a consistent structure:
```
feature/
├── ui/ # UI components
├── model/ # Business logic (state, actions, selectors)
├── api/ # HTTP calls, WebSocket, etc.
├── lib/ # Utilities, helpers
└── index.ts # Public API
```
## Implementation Guidelines
### 1. Shared Layer
```tsx
// shared/ui/button/button.tsx
import React from 'react';
import './button.css';
type ButtonProps = {
variant?: 'primary' | 'secondary' | 'ghost';
size?: 'small' | 'medium' | 'large';
children: React.ReactNode;
onClick?: () => void;
};
export const Button = ({
variant = 'primary',
size = 'medium',
children,
onClick,
...props
}: ButtonProps) => {
return (
<button
className={`button button--${variant} button--${size}`}
onClick={onClick}
{...props}>
{children}
</button>
);
};
```
- Keep components generic and reusable
- Avoid business logic
- Export via a public API
### 2. Entity Layer
```tsx
// entities/product/model/types.ts
export interface Product {
id: string;
title: string;
description: string;
price: number;
imageUrl: string;
}
// entities/product/api/productApi.ts
import { Product } from '../model/types';
export const fetchProducts = async (): Promise<Product[]> => {
const response = await fetch('/api/products');
return response.json();
};
// entities/product/ui/product-card/index.tsx
import React from 'react';
import { Product } from '../../model/types';
import './product-card.css';
interface ProductCardProps {
product: Product;
}
export const ProductCard = ({ product }: ProductCardProps) => {
return (
<div className='product-card'>
<img src={product.imageUrl} alt={product.title} />
<h3>{product.title}</h3>
<p className='product-card__price'>${product.price}</p>
</div>
);
};
// entities/product/index.ts
export { ProductCard } from './ui/product-card';
export { fetchProducts } from './api/productApi';
export type { Product } from './model/types';
```
- Focus on core business entities
- Export a clear public API
- Avoid dependencies on features or higher layers
### 3. Feature Layer
```tsx
// features/cart/add-to-cart/ui/add-to-cart-button.tsx
import React from 'react';
import { Button } from 'shared/ui/button';
import { useAddToCart } from '../model/useAddToCart';
import { Product } from 'entities/product';
interface AddToCartButtonProps {
product: Product;
}
export const AddToCartButton = ({ product }: AddToCartButtonProps) => {
const { addToCart, isLoading } = useAddToCart();
const handleClick = () => {
addToCart(product);
};
return (
<Button onClick={handleClick} disabled={isLoading}>
{isLoading ? 'Adding...' : 'Add to Cart'}
</Button>
);
};
// features/cart/add-to-cart/model/useAddToCart.ts
import { useState } from 'react';
import { Product } from 'entities/product';
import { addProductToCart } from '../api/cartApi';
export const useAddToCart = () => {
const [isLoading, setIsLoading] = useState(false);
const addToCart = async (product: Product) => {
setIsLoading(true);
try {
await addProductToCart(product.id);
// Handle success
} catch (error) {
// Handle error
console.error('Failed to add to cart', error);
} finally {
setIsLoading(false);
}
};
return { addToCart, isLoading };
};
// features/cart/add-to-cart/index.ts
export { AddToCartButton } from './ui/add-to-cart-button';
```
- Implement user interactions
- Use entities but don't modify them directly
- Encapsulate feature-specific logic
- Export only necessary components via index files
### 4. Widget Layer
```tsx
// widgets/product-showcase/ui/product-showcase.tsx
import React, { useEffect, useState } from 'react';
import { ProductCard, Product, fetchProducts } from 'entities/product';
import { AddToCartButton } from 'features/cart/add-to-cart';
import './product-showcase.css';
export const ProductShowcase = () => {
const [products, setProducts] = useState<Product[]>([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const loadProducts = async () => {
try {
const data = await fetchProducts();
setProducts(data);
} catch (error) {
console.error('Failed to load products', error);
} finally {
setIsLoading(false);
}
};
loadProducts();
}, []);
if (isLoading) return <div>Loading products...</div>;
return (
<div className='product-showcase'>
<h2>Featured Products</h2>
<div className='product-showcase__grid'>
{products.map((product) => (
<div key={product.id} className='product-showcase__item'>
<ProductCard product={product} />
<AddToCartButton product={product} />
</div>
))}
</div>
</div>
);
};
// widgets/product-showcase/index.ts
export { ProductShowcase } from './ui/product-showcase';
```
- Compose entities and features
- Create complex UI blocks
- Solve specific business scenarios
### 5. Page Layer
```tsx
// pages/home/ui/home-page.tsx
import React from 'react';
import { ProductShowcase } from 'widgets/product-showcase';
import { Header } from 'widgets/header';
import { Footer } from 'widgets/footer';
import './home-page.css';
export const HomePage = () => {
return (
<div className='home-page'>
<Header />
<main className='home-page__content'>
<section className='home-page__hero'>
<h1>Welcome to Our Store</h1>
</section>
<ProductShowcase />
</main>
<Footer />
</div>
);
};
// pages/home/index.ts
export { HomePage } from './ui/home-page';
```
- Compose widgets and features
- Handle routing concerns
- Don't contain complex business logic
## Best Practices
1. **Layer Dependencies**
- Higher layers can import from lower layers, but not vice versa
- Public APIs should be exposed through index files
- Avoid circular dependencies
2. **Feature Isolation**
- Features should be self-contained
- Features should not directly import from other features
- Cross-feature communication should happen through entities or shared layers
3. **Public API Design**
- Only export what's necessary
- Use barrel files (index.ts) to expose public APIs
- Hide implementation details
4. **File Naming**
- Use kebab-case for folders and files
- Use descriptive, domain-oriented names
- Group related files in folders
5. **Component Organization**
- Follow the segment structure (ui, model, api, lib)
- Keep components focused on single responsibilities
- Co-locate related files
## When to Use Feature Sliced Design
Feature Sliced Design is particularly well-suited for:
- Mid-to-large scale applications
- Projects with complex business domains
- Teams with clear separation of responsibilities
- Applications that need to scale over time
However, it might introduce overhead for small projects. Evaluate if the structure benefits your specific use case before adopting it.